如何在Python的魔法编码说明中指定扩展ASCII(即范围为256)?
我正在使用mako模板来生成专门的配置文件。这些文件中有些包含扩展的ASCII字符(大于127),但是当我使用以下代码时,mako报错说这些字符超出了范围:
## -*- coding: ascii -*-
所以我在想,是否有类似于下面这样的东西:
## -*- coding: eascii -*-
可以让我处理范围在128到256之间的字符。
编辑:
这是文件中出问题的部分的内容:
000001b0 39 c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce |9...............|
000001c0 cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de |................|
000001d0 df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee |................|
000001e0 ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe |................|
000001f0 ff 5d 2b 28 27 73 29 3f 22 0a 20 20 20 20 20 20 |.]+('s)?". |
00000200 20 20 74 6f 6b 65 6e 3a 20 57 4f 52 44 20 20 20 | token: WORD |
00000210 20 20 22 5b 41 2d 5a 61 2d 7a 30 2d 39 c0 c1 c2 | "[A-Za-z0-9...|
00000220 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 |................|
00000230 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 |................|
00000240 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 |................|
00000250 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 5d 2b 28 |.............]+(|
mako抱怨的第一个字符是000001b4。如果我删除这一部分,其他的都能正常工作。插入这一部分后,mako就会报错:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 19: ordinal not in range(128)
无论我在魔法注释行中使用'ASCII'还是'latin-1',都出现同样的错误。
谢谢!
Greg
3 个回答
试着仔细看看你的数据:
000001b0 39 c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce |9...............|
000001c0 cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de |................|
000001d0 df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee |................|
000001e0 ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe |................|
000001f0 ff 5d 2b 28 27 73 29 3f 22 0a 20 20 20 20 20 20 |.]+('s)?". |
00000200 20 20 74 6f 6b 65 6e 3a 20 57 4f 52 44 20 20 20 | token: WORD |
00000210 20 20 22 5b 41 2d 5a61 2d 7a 30 2d 39 c0 c1 c2 | "[A-Za-z0-9...|
00000220 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 |................|
00000230 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 |................|
00000240 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 |................|
00000250 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 5d 2b 28 |.............]+(|
加粗的部分是从0xc0到0xff的每个字节。看起来你有一个二进制文件(可能是编译后的正则表达式的转储),而不是文本文件。我建议你把它当作二进制文件来读取,而不是直接粘贴到你的Python源文件中。你还应该查看mako的文档,了解它期望什么。
更新:在大致浏览了你转储的文本部分后,你可能可以用仅包含ASCII字符的正则表达式来表达这个内容,例如,你会有一行包含
token: WORD "[A-Za-z0-9\xc0-\xff]+(etc)etc"
试试
## -*- coding: UTF-8 -*-
或者
## -*- coding: latin-1 -*-
或者
## -*- coding: cp1252 -*-
具体要看你需要什么。最后两个选项很相似,除了:
Windows-1252编码和ISO-8859-1编码在所有代码上是一样的,只有在128到159这个范围(十六进制的80到9F)时,少用的C1控制字符被替换成了其他字符。Windows-28591实际上就是ISO-8859-1的编码。
其中,ISO-8859-1
是latin-1
的正式名称。
简短回答
用cp437编码来体验一些复古的DOS乐趣。所有大于或等于32(十进制)的字节值,除了127,都可以在这种编码中显示为字符。然后用cp037编码来体验真正奇妙的感觉。接着问问自己,你怎么知道这两者中哪个是“正确”的,或者它们是否都有可能是“正确”的。
详细回答
有一件事你需要忘掉:字节值和字符之间的绝对等价。
现在很多基本的文本编辑器和调试工具,以及Python语言的规范,都暗示字节和字符之间有绝对的对应关系,但实际上并不存在这种关系。比如说,74 6f 6b 65 6e
并不等于“token”。只有在ASCII兼容的字符编码中,这种对应关系才成立。在EBCDIC编码中,“token”对应的字节值是a3 96 92 85 95
,这种编码在今天仍然相当常见。
所以,虽然Python 2.6解释器会把'text' == u'text'
评估为True
,但这其实是不应该的,因为它们只有在假设使用ASCII或兼容编码的情况下才相等,即使如此也不应该被视为相等。(至少'\xfd' == u'\xfd'
是False
,而且会给你一个警告。)Python 3.1会把'text' == b'text'
评估为False
。但即便如此,解释器接受这个表达式也暗示了字节值和字符之间的绝对等价,因为b'text'
被解释器理解为“对'text'
应用ASCII编码后得到的字节串”。
据我所知,今天广泛使用的每种编程语言在设计中都隐含使用了ASCII或ISO-8859-1(拉丁-1)字符编码。在C语言中,char
数据类型实际上就是一个字节。我见过一个Java 1.4的虚拟机,它的构造函数java.lang.String(byte[] data)
假设使用ISO-8859-1编码。大多数编译器和解释器都假设源代码使用ASCII或ISO-8859-1编码(有些允许你更改)。在Java中,字符串的长度实际上是UTF-16编码单元的长度,这对于U+10000
及以上的字符来说可以说是错误的。在Unix中,文件名是字节串,根据终端设置进行解释,这样你就可以open('a\x08b', 'w').write('Say my name!')
。
所以,我们都被我们信任的工具训练和影响,认为'A' 等于 0x41。但实际上并不是。'A'是一个字符,而0x41是一个字节,它们根本不相等。
一旦你明白了这一点,你就能轻松解决你的问题。你只需要决定软件中的哪个部分假设这些字节值使用ASCII编码,并且如何改变这种行为或确保显示不同的字节值。
PS: “扩展ASCII”和“ANSI字符集”这两个说法其实是不准确的。