2010-01-28 4 views
9

У меня есть строка в Юникоде, и мне нужно вернуть первые N символов. Я делаю это:Возврат первых N символов строки unicode

result = unistring[:5] 

но, конечно, длина Юникода строк = длина символов!. Любые идеи? Единственное решение - использовать re?

Edit: Подробнее

unistring = "Μεταλλικα" #Metallica written in Greek letters 
result = unistring[:1] 

ВОЗВРАЩЕНИЕ>?

Я думаю, что строки unicode - это два байта (char), вот почему это происходит. Если я:

result = unistring[:2] 

Я получаю

M

, который является правильным, Таким образом, я должен всегда ломтик * 2 или я должен преобразовать к чему-то?

+0

Уверены ли вы, что у вас есть фактическая строка в Юникоде, а не (скажем) об ошибке с данными UTF-8? Если да, то как вы определяете «характер»? (строки Юникода - это строки кодовых страниц (в сборках UCS-4) или кодеки.) –

+1

От нашего хоста: http://www.joelonsoftware.com/articles/Unicode.html – Will

+0

Будет, пожалуйста, нет. Здесь это не применимо. – Joey

ответ

6

К сожалению, по историческим причинам до Python 3.0 существуют два типа строк. byte strings (str) and Unicode strings (unicode).

Перед объединением в Python 3.0 существует два способа объявить строковый литерал: unistring = "Μεταλλικα", который является байтовой строкой и unistring = u"Μεταλλικα", который является строкой unicode.

Причина, по которой вы видите ?, когда вы делаете result = unistring[:1], состоит в том, что некоторые символы в тексте Unicode не могут быть правильно представлены в строке, отличной от юникода. Вероятно, вы видели такую ​​проблему, если когда-либо использовали действительно старый почтовый клиент и получали электронные письма от друзей в таких странах, как Греция.

Итак, в Python 2.x, если вам нужно обрабатывать Unicode, вам нужно сделать это явно. Взгляните на это введение к работе с Unicode в Python: Unicode HOWTO

+0

"Μεταλλικα" не является строкой ASCII. Это байтовая строка в кодировке, используемой для сохранения сценария. –

+2

Вы правы Марк правильнее ссылаться на них как на строки байтов, а не на строки ASCII, я соответствующим образом обновил ответ. То, что я действительно пытался выразить, было то, что текст ASCII (или эквивалентная строка байта в зависимости от кодовых страниц на вашем компьютере) - единственное, с чем можно безопасно манипулировать байтовыми строками. –

+1

Ссылка Unicode HOWTO мертва – jeremyvillalobos

8

Когда вы говорите:

unistring = "Μεταλλικα" #Metallica written in Greek letters 

Вы не Юникод строка. У вас есть байты в (предположительно) UTF-8. Это не одно и то же. Строка unicode представляет собой отдельный тип данных в Python. Вы получаете Юникода путем декодирования байтовых строк, используя правильную кодировку:

unistring = "Μεταλλικα".decode('utf-8') 

или с помощью Юникода буквального в исходном файле с провозглашением правом кодирования

# coding: UTF-8 
unistring = u"Μεταλλικα" 

Строка Юникода будет делать то, что вы хотите, когда вы сделать unistring[:5].

+0

Вам понадобится «#coding: utf-8» перед примером .decode(), и файл должен быть фактически сохранен в utf-8. Python 2.x по умолчанию использует ASCII при декодировании скриптов. Любое использование символов, отличных от ASCII, требует, чтобы строка #coding объявила кодировку, используемую для сохранения файла. –

+1

В Python 2.5 и более поздних версиях требуется объявление кодирования в любом исходном файле с содержимым, отличным от ASCII, да. (До этого это просто предупреждение.) Объявление кодирования, однако, не изменит смысл кода, так как это всего лишь байты в байтовой таблице. –

+1

-1 Это неверно u «Некоторое испытание Unicode» [: 5] Может выдавать незаконную последовательность, потому что UTF-16 является кодировкой переменной ширины, поэтому строка «Unicode» неверна как строка utf-8 для резки – Artyom

4

Нет правильного прямого подхода к любому типу «строки Unicode».

Даже Python «Unicode» строка UTF-16 имеет символы переменной длины, поэтому вы не можете просто разрезать ustring [: 5]. Поскольку некоторые кодовые коды Юникода могут использовать более одного «символа», т. Е. Суррогатных пар.

Так что, если вы хотите вырезать 5 кодовых точек (обратите внимание, это не символов), так что вы можете анализировать текст, см http://en.wikipedia.org/wiki/UTF-8 и http://en.wikipedia.org/wiki/UTF-16 определения. Поэтому вам нужно использовать несколько бит-масок для определения границ.

Также вы не получите персонажей. Потому что, например. Слово «שָלוֹם» - мир на иврите «Шалом» состоит из 4-х символов и 6 кодовых букв «голень», гласная «буква» «ламед», буква «вав» и гласная «о» и окончательная буква «мэм».

So знак не код точка.

То же самое для большинства западных языков, где буква с диакритикой может быть представлена ​​в виде двух кодовых точек. Найдите пример для «нормализации юникода».

Итак ... Если вам действительно нужны 5 первых символов, вам нужно использовать такие инструменты, как библиотека ICU. Например, есть библиотека ICU для Python, которая предоставляет именованный символ символов.