如何在命令行上使用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的命令行处理)也是一件好事。
答案 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)
事实证明这很简单。不幸的是,找出我的时间比我想象的要长。
快速浏览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>