如何在命令行上处理utf8(使用Perl或Python)?

时间:2012-03-16 01:58:44

标签: python perl utf-8

如何在命令行上使用Perl(或Python)处理utf8?

例如,我试图将每个单词中的字符分开。这对于非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字节字符。

了解如何在Python中完成此操作(即utf8的命令行处理)也是一件好事。

4 个答案:

答案 0 :(得分:24)

“-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'
о д о б р е н и е   з а 

请参阅Grapheme Cluster Boundaries

Python regex module支持\X

答案 1 :(得分:6)

“嘿,”我想,“这在Perl中有多难?”

事实证明这很简单。不幸的是,找出我的时间比我想象的要长。

快速浏览use utf8向我展示现在已经过时了。 Perl的binmode看起来很有希望,但并不完全。

发现有一个Perluniintro引导我Perlunicode说我应该看Perlrun。然后,我发现了我在寻找的东西。

Perl有一个命令行开关-C,它将Perl切换为Unicode。但是,-C命令行开关还需要一些选项。您需要指定unicode中的内容。有一个convenient chart可以显示各种选项。似乎perl -C本身就没问题。这结合了各种选项,相当于-CSDL-C255。但是,这意味着如果您的LOCALE未设置为unicode,则Perl将无法使用Unicode。

相反,您应该使用perl -CSD-perl -C63

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

你只需回答一个问题就可以学到很多东西。

答案 2 :(得分:4)

我不知道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. Unicode的东西真的得到了改进。

以上是上述程序的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值(“bytes”)的类似字符串的对象。这与Python 2.x相反;在Python 2.x中,基本字符串类型是一个字节字符串,Unicode字符串是一个特殊的新东西。

当然没有必要断言编码是UTF-8,但它是一种很好的简单方法来记录我们的意图,并确保默认不会以某种方式改变。

在Python 3中,print()现在是一个函数。而不是在print语句之后附加逗号以使其打印空格而不是换行符的有点奇怪的语法,现在有一个命名关键字参数,可以让你更改结束字符。

注意:在Python 2.x程序中处理输入行后,我最初只有一个print语句,而在Python 3.x程序中则是print()。正如J.F.Sebastian指出的那样,代码是从输入行打印字符,最后一个字符是换行符,因此实际上不需要额外的print语句。

答案 3 :(得分:4)

$ 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>