【问题标题】:Format strings with fixed width (unicode and utf8)固定宽度的格式化字符串(unicode 和 utf8)
【发布时间】:2018-01-28 16:44:41
【问题描述】:

我需要以类似表格的格式解析和输出一些数据。输入采用 unicode 编码。这是测试脚本:

#!/usr/bin/env python

s1 = u'abcd'
s2 = u'\u03b1\u03b2\u03b3\u03b4'

print '1234567890'
print '%5s' % s1
print '%5s' % s2

在像test.py这样的简单调用的情况下,它可以按预期工作:

1234567890 A B C D αβγδ

但如果我尝试将输出重定向到文件test.py > a.txt,我会收到错误:

回溯(最近一次通话最后): 文件“./test.py”,第 8 行,在 打印 '%5s' % s2 UnicodeEncodeError:“ascii”编解码器无法对位置 1-4 中的字符进行编码:序数不在范围内(128)

如果我将字符串转换为 UTF-8 编码,例如 s2.encode('utf8') 重定向工作正常,但数据位置已损坏:

1234567890 A B C D αβγδ

如何强制它在这两种情况下正常工作?

【问题讨论】:

    标签: python linux python-2.7


    【解决方案1】:

    您应该编码'%5s' % s2 而不是s2。所以下面会有预期的输出:

    print ('%5s' % s2).encode('utf8')
    

    【讨论】:

    • 在你回答之后它变得很明显:) 谢谢。
    【解决方案2】:

    print '%5s' % s1 是正确的,但 print '%5s' % s2 是不正确的。一定是print ('%5s' % s2).encode('utf8')

    试试这个代码。

    #!/usr/bin/env python
    
    s1 = u'abcd'
    s2 = u'\u03b1\u03b2\u03b3\u03b4'
    
    print '1234567890' 
    print '%5s' % s1
    print ('%5s' % s2).encode('utf8')
    

    【讨论】:

      【解决方案3】:

      归结为您的输出流编码。在这种特殊情况下,由于您使用的是print,因此使用的输出文件是sys.stdout

      交互模式/stdout 未重定向

      当你以交互模式运行 Python 时,或者当你不将stdout 重定向到文件时,Python 使用基于环境的编码,即语言环境变量,如LC_CTYPE。例如,如果您像这样运行程序:

      $ LC_CTYPE='en_US' python test.py
      ...
      UnicodeEncodeError: 'ascii' codec can't encode characters in position 1-4: ordinal not in range(128)
      

      它将使用ANSI_X3.4-1968 代替sys.stdout(参见sys.stdout.encoding)并失败。但是,您是否使用UTF-8(显然您已经这样做了):

      $ LC_CTYPE='en_US.UTF-8' python test.py
      1234567890
       abcd
       αβγδ
      

      你会得到预期的输出。

      stdout 重定向到文件

      当您将stdout 重定向到文件时,Python 不会尝试从您的环境语言环境中检测编码,但它会检查另一个环境变量PYTHONIOENCODING(检查源代码initstdio() in Python/pylifecycle.c)。例如,这将按预期工作:

      $ PYTHONIOENCODING=utf-8 python test.py >/tmp/output
      

      因为 Python 将对/tmp/output 文件使用UTF-8 编码。

      手动stdout编码覆盖

      您也可以使用所需的编码手动重新打开sys.stdout(检查thisthis SO 问题):

      import sys
      import codecs
      sys.stdout = codecs.getwriter('utf8')(sys.stdout)
      

      现在print 将正确输出strunicode 对象,因为底层流编写器会将它们即时转换为UTF-8

      输出前手动编码字符串

      当然,您也可以在输出之前手动将每个unicode 编码为UTF-8 str

      print ('%5s' % s2).encode('utf8')
      

      但这很乏味且容易出错。

      显式文件打开

      为了完整性:在 Python 2 中打开文件以使用特定编码(如 UTF-8)进行写入时,您应该使用io.opencodecs.open,因为它们允许您指定编码(请参阅this question) ,不像内置的open

      from codecs import open
      myfile = open('filename', encoding='utf-8')
      

      或:

      from io import open
      myfile = open('filename', encoding='utf-8')
      

      【讨论】:

      • 感谢您解释为什么它在有和没有重定向的情况下以不同的方式工作。
      • 不客气。我想把所有的方法都放在一个地方,因为我发现它们都是零散的。
      猜你喜欢
      • 2012-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-15
      • 1970-01-01
      • 2016-11-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多