首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何修复将Python迁移到unicode_literals的编码?

如何修复将Python迁移到unicode_literals的编码?
EN

Stack Overflow用户
提问于 2014-12-31 14:55:18
回答 2查看 8.3K关注 0票数 5

我们准备转到Python3.4并添加unicode_literals。我们的代码广泛地依赖于使用子处理模块往返外部实用程序的管道。以下代码片段在Python2.7上可以很好地将UTF-8字符串输送到子进程:

代码语言:javascript
复制
kw = {}
kw[u'stdin'] = subprocess.PIPE
kw[u'stdout'] = subprocess.PIPE
kw[u'stderr'] = subprocess.PIPE
kw[u'executable'] = u'/path/to/binary/utility'
args = [u'', u'-l', u'nl']

line = u'¡Basta Ya!'

popen = subprocess.Popen(args,**kw)
popen.stdin.write('%s\n' % line.encode(u'utf-8'))
...blah blah...

以下更改会引发此错误:

代码语言:javascript
复制
from __future__ import unicode_literals

kw = {}
kw[u'stdin'] = subprocess.PIPE
kw[u'stdout'] = subprocess.PIPE
kw[u'stderr'] = subprocess.PIPE
kw[u'executable'] = u'/path/to/binary/utility'
args = [u'', u'-l', u'nl']

line = u'¡Basta Ya!'

popen = subprocess.Popen(args,**kw)
popen.stdin.write('%s\n' % line.encode(u'utf-8'))
Traceback (most recent call last):
  File "test.py", line 138, in <module>
    exitcode = main()
  File "test.py", line 57, in main
    popen.stdin.write('%s\n' % line.encode('utf-8'))
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 0: ordinal not in range(128)

有什么建议让UTF-8通过管道吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-12-31 14:58:17

'%s\n'是使用unicode_literals时的unicode字符串。

代码语言:javascript
复制
>>> line = u'¡Basta Ya!'
>>> '%s\n' % line.encode(u'utf-8')
'\xc2\xa1Basta Ya!\n'
>>> u'%s\n' % line.encode(u'utf-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 0: ordinal not in range(128)

所发生的情况是将编码的line值解码为将其插入到unicode '%s\n'字符串中。

您将不得不使用字节字符串;将字符串前缀为b

代码语言:javascript
复制
>>> from __future__ import unicode_literals
>>> line = u'¡Basta Ya!'
>>> b'%s\n' % line.encode(u'utf-8')
'\xc2\xa1Basta Ya!\n'

或在插值后编码:

代码语言:javascript
复制
>>> line = u'¡Basta Ya!'
>>> ('%s\n' % line).encode(u'utf-8')
'\xc2\xa1Basta Ya!\n'

在Python 3中,您必须将字节串写到管道中。

票数 6
EN

Stack Overflow用户

发布于 2015-01-05 08:01:54

如果utf-8代表您的地区编码,那么使用Unicode字符串进行通信,您可以在Python3上使用universal_newlines=True

代码语言:javascript
复制
#!/usr/bin/env python3
from subprocess import Popen, PIPE

p = Popen(['/path/to/binary/utility', '-l', 'nl'],
          stdin=PIPE, stdout=PIPE, stderr=PIPE,
          universal_newlines=True)
out, err = p.communicate('¡Basta Ya!')

即使区域设置的编码不是utf-8,代码也能工作。输入/输出是这里的Unicode字符串(str类型)。

如果子进程需要utf-8,那么无论当前区域设置是什么,都可以使用字节串(pass/read字节)进行通信:

代码语言:javascript
复制
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import os
from subprocess import Popen, PIPE

p = Popen(['/path/to/binary/utility', '-l', 'nl'],
          stdin=PIPE, stdout=PIPE, stderr=PIPE)
out, err = map(lambda b: b.decode('utf-8').replace(os.linesep, '\n'),
               p.communicate((u'¡Basta Ya!' + os.linesep).encode('utf-8')))

这些代码在Python 2和3上都是一样的。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27722720

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档