как проверить, является ли строка юникодом или ascii?

<p>что мне нужно сделать в python, чтобы выяснить, какую кодировку имеет строка?</p>

<p>в python 3 все строки являются последовательностями символов юникода. существует тип <code>bytes</code>, который содержит необработанные байты.</p><p>в python 2 строка может быть типа <code>str</code> или типа <code>unicode</code>. вы можете сказать, что с помощью кода примерно так:</p><pre><code>def whatisthis(s): if isinstance(s, str): print "ordinary string" elif isinstance(s, unicode): print "unicode string" else: print "not a string" </code></pre><p>это не различает "unicode или ascii"; он различает только типы python. строка unicode может состоять из чисто символов в диапазоне ascii, а строка байтов может содержать ascii, закодированный unicode или даже нетекстовые данные.</p>

<h2>как определить, является ли объект строкой unicode или строкой байтов</h2><p>вы можете использовать <code>type</code> или <code>isinstance</code>.</p><p>в python 2:</p><pre><code>>>> type(u'abc') # python 2 unicode string literal <type 'unicode'> >>> type('abc') # python 2 byte string literal <type 'str'> </code></pre><p>в python 2 <code>str</code> - это просто последовательность байтов. python не знает, какова его кодировка. тип <code>unicode</code> - более безопасный способ хранения текста. если вы хотите понять это больше, я рекомендую <a href="http://farmdev.com/talks/unicode/">http://farmdev.com/talks/unicode/</a> .</p><p>в python 3:</p><pre><code>>>> type('abc') # python 3 unicode string literal <class 'str'> >>> type(b'abc') # python 3 byte string literal <class 'bytes'> </code></pre><p>в python 3 <code>str</code> похож на python 2 <code>unicode</code> и используется для хранения текста. то, что называлось <code>str</code> в python 2, называется <code>bytes</code> в python 3.</p><hr><h2>как определить, действительна ли байтовая строка utf-8 или ascii?</h2><p>вы можете позвонить <code>decode</code>. если оно вызывает исключение unicodedecodeerror, оно недопустимо.</p><pre><code>>>> u\_umlaut = b'\xc3\x9c' # utf-8 representation of the letter 'ü' >>> u\_umlaut.decode('utf-8') u'\xdc' >>> u\_umlaut.decode('ascii') traceback (most recent call last): file "<stdin>", line 1, in <module> unicodedecodeerror: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128) </code></pre>

<p>в python 3.x все строки являются последовательностями символов юникода. и достаточно выполнить проверку isinstance для str (что по умолчанию означает строку unicode).</p><pre><code>isinstance(x, str) </code></pre><p>что касается python 2.x, большинство людей, похоже, используют оператор if, который имеет две проверки. один для ул и один для юникода.</p><p>если вы хотите проверить, есть ли у вас "строковый" объект с одним оператором, вы можете сделать следующее:</p><pre><code>isinstance(x, basestring) </code></pre>

<p>юникод не является кодировкой, - цитирую кумара макмиллана:</p><blockquote> <p>если ascii, utf-8 и другие байтовые строки являются "текстовыми" ...</p> <p>... тогда юникод это "текст-несс";</p> <p>это абстрактная форма текста</p> </blockquote><p>прочитайте разговор макмиллана <a href="http://farmdev.com/talks/unicode/">nicode in python, полностью демистифицированный</a> из pycon 2008, он объясняет вещи намного лучше, чем большинство связанных ответов о переполнении стека.</p>

<p>если ваш код должен быть совместим с <strong>обе</strong> python 2 и python 3, вы не можете напрямую использовать такие вещи, как <code>isinstance(s,bytes)</code> или <code>isinstance(s,unicode)</code>, не заключая их ни в одну из них. попробуйте/исключить или python версия теста, потому что <code>bytes</code> не определено в python 2, а <code>unicode</code> не определено в python 3.</p><p>есть некоторые уродливые обходные пути. чрезвычайно уродливо сравнивать <em> имя </em> типа, а не сравнивать сам тип. вот пример:</p><pre><code># convert bytes (python 3) or unicode (python 2) to str if str(type(s)) == "<class 'bytes'>": # only possible in python 3 s = s.decode('ascii') # or s = str(s)[2:-1] elif str(type(s)) == "<type 'unicode'>": # only possible in python 2 s = str(s) </code></pre><p>возможно, немного менее уродливый обходной путь - проверить номер версии python, например:</p><pre><code>if sys.version\_info >= (3,0,0): # for python 3 if isinstance(s, bytes): s = s.decode('ascii') # or s = str(s)[2:-1] else: # for python 2 if isinstance(s, unicode): s = str(s) </code></pre><p>они оба не пифоничны, и в большинстве случаев, вероятно, есть лучший способ.</p>

<p>использовать:</p><pre><code>import six if isinstance(obj, six.text\_type) </code></pre><p>внутри шести библиотек она представлена в виде:</p><pre><code>if py3: string\_types = str, else: string\_types = basestring, </code></pre>

<p>обратите внимание, что в python 3 не совсем справедливо сказать следующее:</p><ul> <li> <p><code>str</code>s - это utfx для любого x (например, utf8)</p> </li> <li> <p><code>str</code>s - это юникод</p> </li> <li> <p><code>str</code>s - упорядоченные наборы символов юникода</p> </li> </ul><p>тип python <code>str</code> (обычно) представляет собой последовательность кодовых точек unicode, некоторые из которых отображаются на символы.</p><hr><p>даже на python 3 ответить на этот вопрос не так просто, как вы можете себе представить.</p><p>очевидный способ проверки ascii-совместимых строк - попытка кодирования:</p><pre><code>"hello there!".encode("ascii") #>>> b'hello there!' "hello there... ☃!".encode("ascii") #>>> traceback (most recent call last): #>>> file "", line 4, in <module> #>>> unicodeencodeerror: 'ascii' codec can't encode character '\u2603' in position 15: ordinal not in range(128) </code></pre><p>ошибка различает случаи.</p><p>в python 3 даже есть несколько строк, которые содержат недопустимые кодовые точки unicode:</p><pre><code>"hello there!".encode("utf8") #>>> b'hello there!' "\udcc3".encode("utf8") #>>> traceback (most recent call last): #>>> file "", line 19, in <module> #>>> unicodeencodeerror: 'utf-8' codec can't encode character '\udcc3' in position 0: surrogates not allowed </code></pre><p>используется тот же метод, чтобы различать их.</p>

<p>это может помочь кому-то еще, я начал тестировать строковый тип переменной s, но для моего приложения было больше смысла просто возвращать s как utf-8. процесс, вызывающий return\_utf, затем знает, с чем имеет дело, и может соответствующим образом обработать строку. код не является чистым, но я намерен сделать его независимым от версии [python без проверки версии или импорта шести). пожалуйста, прокомментируйте улучшения в приведенном ниже примере кода, чтобы помочь другим людям.</p><pre><code>def return\_utf(s): if isinstance(s, str): return s.encode('utf-8') if isinstance(s, (int, float, complex)): return str(s).encode('utf-8') try: return s.encode('utf-8') except typeerror: try: return str(s).encode('utf-8') except attributeerror: return s except attributeerror: return s return s # assume it was already utf-8 </code></pre>

<p>вы можете использовать <a href="https://pypi.python.org/pypi/chardet">niversal encoding detector</a> , но имейте в виду, что он просто даст вам лучшее предположение, а не фактическую кодировку, потому что невозможно узнать кодировку строки "abc", например. вам нужно будет получить информацию о кодировке в другом месте, например, протокол http для этого использует заголовок content-type.</p>

<p>для совместимости с py2/py3 просто используйте</p><p><code>import six if isinstance(obj, six.text\_type)</code></p>