Как заставить интерпретатор python правильно обрабатывать символы, отличные от ASCII, в строковых операциях?

У меня есть строка, которая выглядит так:

6 918 417 712

Четкий способ обрезать эту строку (как я понимаю, Python) просто сказать, что строка находится в переменной с именем s, мы получаем:

s.replace('Â ', '')

Это должно сделать трюк. Но, конечно, он жалуется, что символ не-ASCII '\xc2' в файле blabla.py не закодирован.

Я никогда не мог понять, как переключаться между разными кодировками.

Вот код, он действительно такой же, как и выше, но теперь он в контексте. Файл сохраняется как UTF-8 в блокноте и имеет следующий заголовок:

#!/usr/bin/python2.4
# -*- coding: utf-8 -*-

Код:

f = urllib.urlopen(url)

soup = BeautifulSoup(f)

s = soup.find('div', {'id':'main_count'})

#making a print 's' here goes well. it shows 6Â 918Â 417Â 712

s.replace('Â ','')

save_main_count(s)

Он не превышает s.replace...

Ответ 1

Python 2 использует ascii как кодировку по умолчанию для исходных файлов, а это означает, что вы должны указать другую кодировку в верхней части файла, чтобы использовать символы un-ascii unicode в литералах. Python 3 использует utf-8 как кодировку по умолчанию для исходных файлов, поэтому это не проблема.

См: http://docs.python.org/tutorial/interpreter.html#source-code-encoding

Чтобы включить кодировку исходного кода utf-8, это будет проходить в одной из двух верхних строк:

# -*- coding: utf-8 -*-

Вышеупомянутое находится в документах, но это также работает:

# coding: utf-8

Дополнительные соображения:

  • Исходный файл должен быть сохранен с использованием правильной кодировки в текстовом редакторе.

  • В Python 2 литерал unicode должен иметь перед ним u, как в s.replace(u"Â ", u"") Но в Python 3 просто используйте кавычки. В Python 2 вы можете from __future__ import unicode_literals получить поведение Python 3, но помните, что это влияет на весь текущий модуль.

  • s.replace(u"Â ", u"") также будет терпеть неудачу, если s не является строкой unicode.

  • string.replace возвращает новую строку и не редактируется на месте, поэтому убедитесь, что вы также используете возвращаемое значение

Ответ 2

def removeNonAscii(s): return "".join(filter(lambda x: ord(x)<128, s))

edit: мой первый импульс всегда использует фильтр, но выражение генератора более эффективно (и короче) памяти...

def removeNonAscii(s): return "".join(i for i in s if ord(i)<128)

Имейте в виду, что это гарантировано для работы с кодировкой UTF-8 (поскольку все байты в многобайтовых символах имеют самый старший бит, установленный в 1).

Ответ 3

>>> unicode_string = u"hello aåbäcö"
>>> unicode_string.encode("ascii", "ignore")
'hello abc'

Ответ 4

Следующий код заменит все символы без символов ASCII вопросительными знаками.

"".join([x if ord(x) < 128 else '?' for x in s])

Ответ 5

Использование Regex:

import re

strip_unicode = re.compile("([^[email protected]#%&=,/'\";:~`\$\^\*\(\)\+\[\]\.\{\}\|\?\<\>\\]+|[^\s]+)")
print strip_unicode.sub('', u'6Â 918Â 417Â 712')

Ответ 6

Слишком поздно для ответа, но исходная строка была в UTF-8, а '\ xc2\xa0' - это UTF-8 для NO-BREAK SPACE. Просто декодируйте исходную строку как s.decode('utf-8') (\ xa0 отображается как пространство при некорректном декодировании как Windows-1252 или latin-1:

Пример (Python 3)

s = b'6\xc2\xa0918\xc2\xa0417\xc2\xa0712'
print(s.decode('latin-1')) # incorrectly decoded
u = s.decode('utf8') # correctly decoded
print(u)
print(u.replace('\N{NO-BREAK SPACE}','_'))
print(u.replace('\xa0','-')) # \xa0 is Unicode for NO-BREAK SPACE

Выход

6 918 417 712
6 918 417 712
6_918_417_712
6-918-417-712

Ответ 7

#!/usr/bin/env python
# -*- coding: utf-8 -*-

s = u"6Â 918Â 417Â 712"
s = s.replace(u"Â", "") 
print s

Откроется 6 918 417 712

Ответ 8

Я знаю, что это старый поток, но я был вынужден упомянуть о методе перевода, который всегда является хорошим способом заменить все коды символов выше 128 (или, если необходимо, на другие).

Использование: str. translate (таблица [, deletechars])

>>> trans_table = ''.join( [chr(i) for i in range(128)] + [' '] * 128 )

>>> 'Résultat'.translate(trans_table)
'R sultat'
>>> '6Â 918Â 417Â 712'.translate(trans_table)
'6  918  417  712'

Начиная с Python 2.6, вы также можете установить таблицу в None и использовать deletechars для удаления символов, которые вы не хотите, как в примерах, показанных в стандартных документах, в http://docs.python.org/library/stdtypes.html.

С строками unicode таблица переводов не является строкой из 256 символов, а dict с символом ord() соответствующих символов в качестве ключей. Но в любом случае получение правильной строки ascii из строки unicode достаточно просто, используя метод, упомянутый truppo выше, а именно: unicode_string.encode( "ascii", "ignore" )

В качестве сводки, если по какой-то причине вам абсолютно необходимо получить строку ascii (например, когда вы поднимаете стандартное исключение с помощью raise Exception, ascii_message), вы можете использовать следующую функцию:

trans_table = ''.join( [chr(i) for i in range(128)] + ['?'] * 128 )
def ascii(s):
    if isinstance(s, unicode):
        return s.encode('ascii', 'replace')
    else:
        return s.translate(trans_table)

Хорошая вещь в переводе состоит в том, что вы можете фактически преобразовать символы с акцентом в соответствующие символы без акцента ascii вместо простого удаления или замены их на??. Это часто полезно, например, для целей индексирования.

Ответ 9

s.replace(u'Â ', '')              # u before string is important

и сделайте ваш unicode файл .py.

Ответ 10

Это грязный взлом, но он может работать.

s2 = ""
for i in s:
    if ord(i) < 128:
        s2 += i

Ответ 11

Для чего это стоило, мой набор символов был utf-8, и я включил классическую строку # -*- coding: utf-8 -*-.

Тем не менее, я обнаружил, что у меня не было Universal Newlines при чтении этих данных с веб-страницы.

В моем тексте было два слова, разделенных "\r\n". Я только разбился на \n и заменил "\n".

Как только я зациклился и увидел набор символов, я понял ошибку.

Таким образом, он также может быть в наборе символов ASCII, но символа, которого вы не ожидали.