Как обрабатывать utf8 в командной строке (используя Perl или Python)? - PullRequest
15 голосов
/ 16 марта 2012

Как я могу обработать utf8, используя Perl (или Python) в командной строке?

Например, я пытаюсь разбить символы в каждом слове. Это очень просто для текста не-utf8, например:

$ echo "abc def" | perl -ne 'my @letters = m/(.)/g; print "@letters\n"' | less
a b c   d e f

Но с utf8 это не работает, конечно:

$ echo "одобрение за" | perl -ne 'my @letters = m/(.)/g; print "@letters\n"' | less
<D0> <BE> <D0> <B4> <D0> <BE> <D0> <B1> <D1> <80> <D0> <B5> <D0> <BD> <D0> <B8> <D0> <B5>   <D0> <B7> <D0> <B0>

потому что он не знает о 2-байтовых символах.

Было бы также полезно узнать, как это делается (то есть обработка utf8 в командной строке) в Python.

Ответы [ 4 ]

26 голосов
/ 16 марта 2012

Флаг "-C" управляет некоторыми функциями Perl Unicode (см. perldoc perlrun):

$ echo "одобрение за" | perl -C -pe 's/.\K/ /g'
о д о б р е н и е   з а 

Чтобы указать кодировку, используемую для stdin / stdout, вы можете использовать PYTHONIOENCODING переменную среды:

$ echo "одобрение за" | PYTHONIOENCODING=utf-8 python -c'import sys
for line in sys.stdin:
    print " ".join(line.decode(sys.stdin.encoding)),
'
о д о б р е н и е   з а 

Если вы хотите разбить текст на границы символов (графемы) (а не на кодовые точки, как в приведенном выше коде), вы можете использовать /\X/ регулярное выражение:

$ echo "одобрение за" | perl -C -pe 's/\X\K/ /g'
о д о б р е н и е   з а 

См. Границы кластера графема

В Python \X поддерживается regex module .

6 голосов
/ 16 марта 2012

«Привет», подумал я, «как сложно это может быть в Perl?»

Оказывается, это довольно легко.К сожалению, выяснение того, как заняло у меня больше времени, чем я думал.

Быстрый взгляд на use utf8 показал мне, что это уже устарело. binmode в Perl выглядел многообещающе, но не совсем.

Обнаружил, что есть Perluniintro , который привел меня к Perlunicode , который сказал, что я должен смотреть на PerlRun .Затем я нашел то, что искал.

В Perl есть переключатель командной строки -C, который переключает Perl в Unicode.Однако для параметра командной строки -C также требуется несколько параметров.Вам нужно указать, что в юникоде.Есть удобный график , который показывает различные варианты.Казалось бы, perl -C само по себе было бы хорошо.Это сочетает в себе различные варианты, что эквивалентно -CSDL или -C255.Тем не менее, это означает, что если в вашем LOCALE не установлен Unicode, Perl не будет работать в Unicode.

Вместо этого вы должны использовать perl -CSD или -perl -C63.

$ echo "одобрение за" | perl -CSD -ne 'my @letters = m/(.)/g; print "@letters\n"'
о д о б р е н и е   з а

Да, это работает.

Вы можете узнать немного, просто ответив на вопрос.

4 голосов
/ 16 марта 2012
$ echo "одобрение за" | python -c 'import sys, codecs ; x = codecs.
getreader("utf-8")(sys.stdin); print u", ".join(x.read().strip())'
о, д, о, б, р, е, н, и, е,  , з, а

или, если вы хотите кодовые точки Unicode:

$ echo "одобрение за" | python -c 'import sys, codecs ; x = codecs.
getreader("utf-8")(sys.stdin); print u", ".join("<%04x>" % ord(ch) 
for ch in x.read().strip())'
<043e>, <0434>, <043e>, <0431>, <0440>, <0435>, <043d>, <0438>, 
<0435>, <0020>, <0437>, <0430> 
4 голосов
/ 16 марта 2012

Я не знаю Perl, поэтому отвечаю за Python.

Python не знает, что входной текст в Unicode. Вам нужно явно декодировать из UTF-8 или что-то еще, в Unicode. Затем вы можете использовать обычные средства обработки текста Python для его обработки.

http://docs.python.org/howto/unicode.html

Вот простая программа на Python 2.x, которую вы можете попробовать:

import sys

for line in sys.stdin:
    u_line = unicode(line, encoding="utf-8")
    for ch in u_line:
        print ch, # print each character with a space after

Копирует строки из стандартного ввода и преобразует каждую строку в Unicode. Кодировка указана как UTF-8. Затем for ch in u_line устанавливает ch для каждого символа. Тогда print ch, - это простой способ в Python 2.x напечатать символ с пробелом без возврата каретки. Наконец, голый print добавляет возврат каретки.

Я до сих пор использую Python 2.x для большей части своей работы, но для Unicode я бы порекомендовал вам использовать Python 3.x. Уникод действительно улучшен.

Вот версия вышеуказанной программы на Python 3, протестированная на моем компьютере с Linux.

import sys

assert(sys.stdin.encoding == 'UTF-8')
for line in sys.stdin:
    for ch in line:
        print(ch, end=' ') # print each character with a space after

По умолчанию Python 3 предполагает, что вход кодируется как UTF-8. По умолчанию Python затем декодирует это в Unicode. Строки Python 3 всегда Unicode; есть специальный тип bytes(), используемый для строкового объекта, который содержит не-Unicode значения («байты»). Это противоположность Python 2.x; в Python 2.x базовый тип строки представлял собой строку байтов, а строка Юникода была новой особой вещью.

Конечно, нет необходимости утверждать, что кодировка UTF-8, но это хороший простой способ документировать наши намерения и убедиться, что значение по умолчанию не изменилось каким-либо образом.

В Python 3 print() теперь является функцией. И вместо этого несколько странного синтаксиса добавления запятой после оператора print, чтобы заставить ее печатать пробел вместо новой строки, теперь есть аргумент именованного ключевого слова, который позволяет изменить конечный символ.

ПРИМЕЧАНИЕ: Изначально у меня был голый оператор print после обработки строки ввода в программе Python 2.x и print() в программе Python 3.x. Как отметил Дж.Ф. Себастьян, код печатает символы из строки ввода, а последний символ будет новой строкой, поэтому в дополнительном операторе печати нет необходимости.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...