命令行参数解析器argparse不能读取Unicode吗?

13

运行 Python 2.7

执行时:

$ python client.py get_emails -a "åäö"

我理解的是:

usage: client.py get_emails [-h] [-a AREA] [-t {rfc2822,plain}]
client.py get_emails: error: argument -a/--area: invalid unicode value: '\xc3\xa5\xc3\xa4\xc3\xb6'

这是我的解析器:
def _argparse():
    desc = """
           Simple CLI-client for...
           """
    argparser = argparse.ArgumentParser(description=desc)
    subparsers = argparser.add_subparsers(dest='command')

    # create the parser for the "get_emails" command
    parser_get_emails = subparsers.add_parser('get_emails', help=u'Get email list')
    parser_get_emails.add_argument('-a', '--area', type=unicode, help='Limit to area')
    parser_get_emails.add_argument('-t', '--out_type', choices=['rfc2822', 'plain'],
                                   default='rfc2822', help='Type of output')

    args = argparser.parse_args()
    return args

这是否意味着我不能在Python的argparse模块中使用任何Unicode字符?

你的终端编码是什么? - BrenBarn
1
你的终端使用UTF-8编码,但Python默认使用ASCII编码,所以unicode在将字节转换为unicode对象时使用了错误的编码方式。 - chepner
2个回答

17

你可以尝试一下

type=lambda s: unicode(s, 'utf8')

相比之下

type=unicode

如果未提供编码参数,unicode() 函数默认使用 ASCII 编码。


好的,明天我再坐在电脑前测试一下。我在考虑使用 lambda s: unicode(s, locale.getdefaultlocale()[1]) 这种方式,这样应该更灵活。有什么需要注意的吗? - Niclas Nilsson
2
@NiclasNilsson:getdefaultlocale在某些情况下可能会返回None,None,因此您需要一个备用方案,例如getdefaultlocale()[1]或'utf8' - gog
1
请使用 sys.getfilesystemencoding() 而不是硬编码 utf8 来获取文件系统的编码。 - jfs
这比 locale.getdefaultlocale()[1] 更安全吗? - Niclas Nilsson
1
@NiclasNilsson:我对非Unicode控制台的经验很少,但是这里有人说getfilesystemencoding不是argv编码。然而,它可能是sys.stdin.encoding - gog
2
@georg:我在您提供的链接中没有看到sys.getfilesystemencoding()提到。您为什么认为sys.argv项不在sys.getfilesystemencoding()中?存在无法解码的参数问题,但这是一个不同的问题。 - jfs

15
命令行参数使用 sys.getfilesystemencoding() 进行编码:
import sys

def commandline_arg(bytestring):
    unicode_string = bytestring.decode(sys.getfilesystemencoding())
    return unicode_string

# ...
parser_get_emails.add_argument('-a', '--area', type=commandline_arg)

注意:在Python 3中不需要此操作(参数已经是Unicode)。在这种情况下,它使用os.fsdecode(),因为有时命令行参数可能无法解码。请参见PEP 383 -- Non-decodable Bytes in System Character Interfaces


1
实际上,如果需要支持当前本地编码无法解码的文件名(在Windows上使用Unicode API,在Linux上配置不正确的区域设置),则实际答案可能更加复杂。有关详细信息,请参见如何处理具有俄罗斯字符的路径?(如果需要翻译,请询问)。 - jfs
这个对我有用。在我的情况下,参数值是一个中文字符的字符串。被接受的答案抱怨“无效的 <lambda> 值:”。 - ElpieKay

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接