从终端解释Unicode

时间:2014-12-11 01:15:57

标签: python unicode terminal

我在从shell中读取Unicode文本到Python时遇到问题。我有一个测试文档,其中包含以下元数据:

kMDItemAuthors = (
    "To\U0304ny\U0308 Sta\U030ark"
)

我在运行mdls -name kMDItemAuthors path/to/the/file

时看到了这一点

我试图在Python脚本中将这些数据转换为可用的形式。但是,我无法将Unicode表示的文本转换为Python中的实际Unicode。

以下是我目前正在做的事情:

import unicodedata
import subprocess
import os
os.environ['LANG'] = 'en_US.UTF-8'
cmd = 'mdls -name kMDItemAuthors path/to/the/file'
proc = subprocess.Popen(cmd,
                        shell=True,
                        stdin=subprocess.PIPE,
                        stdout=subprocess.PIPE,
                        stderr=subprocess.PIPE)
(stdout, stderr) = proc.communicate()
u = unicode(stdout, 'utf8')
a = unicodedata.normalize('NFC', u)

现在,当我print(a)时,我得到完全相同的字符串表示。我尝试使用所有选项(NFCNFDNFKCNFKD)进行规范化,所有选项都具有相同的结果。

更奇怪的是,当我尝试这段代码时:

print('To\U0304ny\U0308 Sta\U030ark')

我收到以下错误:

SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 2-7: truncated \UXXXXXXXX escape

因此,当该子字符串在变量中时,没有问题,但作为原始字符串,它会产生问题。

我对Python和Unicode的理解非常强烈,但现在shell已经打破了我。任何帮助将不胜感激。

PS。我在Python 2.7.X中运行所有这些

3 个答案:

答案 0 :(得分:2)

这里有多个问题。

  • 与所有转义序列一样,Python仅解释源代码中字符串文字中的\U序列。如果文件中实际上有\后跟U,则Python不会将其视为\U以外的任何内容而不是将\后跟n作为换行符。如果您想手动手动,可以使用unicodeescape编解码器。 (但请注意,这会将您的文件视为ASCII,而不是UTF-8。如果您实际上同时具有UTF-8 \U序列,则必须将其解码为UTF8,然后使用unicodeescape对其进行编码,然后使用unicodeescape对其进行解码。)
  • Python \U序列需要8个数字,而不是4个。如果您只有4个,则必须使用\u。因此,无论程序生成此字符串,都无法使用unicodeescape进行解析。您可以通过s.replace(r'\U', r'\U0000')s.replace('r\U', r'\u')之类的快速和肮脏的解决方法来破解它,或者您可能必须为它编写一个简单的解析器。
  • 在测试中,您尝试在字符串文字中使用\U转义符。您只能在 Unicode 字符串文字中执行此操作,例如print(u'To\U0304ny\U0308 Sta\U030ark')。 (如果你这样做,当然,你会再次得到上一个错误。)

此外,由于这似乎是Mac,您可能不应该os.environ['LANG'] = 'en_US.UTF-8'。如果Python看到它在OS X上,它假设一切都是UTF-8。你试图强制使用UTF-8的任何东西都可能什么也不做,理论上可能会混淆它,所以它不会注意到它在OS X上。除非你试图解决一个驱动程序在调用脚本之前故意将语言环境设置为“C”,通常最好不要这样做。

答案 1 :(得分:1)

正如其他答案中提到的稍微更直接的代码示例

>>> s="To\U0304ny\U0308 Sta\U030ark"
>>> s
'To\\U0304ny\\U0308 Sta\\U030ark'
>>> s.replace("\\U","\\u").decode("unicode-escape")
u'To\u0304ny\u0308 Sta\u030ark'
>>> print s.replace("\\U","\\u").decode("unicode-escape")
Tōnÿ Stårk
>>> 

答案 2 :(得分:0)

\U用于BMP之外的字符,即它需要8个十六进制数字。对于BMP中的字符,请使用\u

>>> print u'To\u0304ny\u0308 Sta\u030ark'
Tōnÿ Stårk

3>> print('To\u0304ny\u0308 Sta\u030ark')
Tōnÿ Stårk