12

我正在使用 mako 模板来生成专门的配置文件。其中一些文件包含扩展的 ASCII 字符 (>127),但是当我使用时 mako 窒息说这些字符超出了范围:

## -*- coding: ascii -*-

所以我想知道是否可能有类似的东西:

## -*- coding: eascii -*-

我可以使用 range(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”,都是同样的抱怨。

谢谢!

格雷格

4

3 回答 3

19

简短的回答

使用 cp437 作为一些复古 DOS 乐趣的编码。除 127 外,所有大于或等于十进制 32 的字节值都映射到此编码中的可显示字符。然后使用 cp037 作为真正的迷幻时间的编码。然后问问自己,如果其中任何一个是“正确的”,您如何真正知道其中哪一个是“正确的”。

长答案

你必须忘掉一些东西:字节值和字符的绝对等价。

今天许多基本的文本编辑器和调试工具,以及 Python 语言规范,都暗示了字节和字符之间的绝对等价,而实际上并不存在。74 6f 6b 65 6e 不是“令牌”。仅对于与 ASCII 兼容的字符编码,此对应关系才有效。在今天仍然很常见的 EBCDIC 中,“令牌”对应于字节值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'被解释器理解为“当你将 ASCII 编码应用于'text'”时得到的字节串。

据我所知,当今广泛使用的每种编程语言在其设计中的某处都隐含使用了 ASCII 或 ISO-8859-1 (Latin-1) 字符编码。在 C 中,char数据类型实际上是一个字节。我看到一个 Java 1.4 VM,其中构造函数java.lang.String(byte[] data)采用 ISO-8859-1 编码。大多数编译器和解释器假定源代码为 ASCII 或 ISO-8859-1 编码(有些允许您更改它)。U+10000在 Java 中,字符串长度实际上是 UTF-16 代码单元长度,这对于字符及以上字符来说可能是错误的。在 Unix 中,文件名是根据终端设置解释的字节字符串,允许您将open('a\x08b', 'w').write('Say my name!').

所以我们都接受了我们已经学会信任的工具的训练和训练,相信“A”0x41。但事实并非如此。'A' 是一个字符,0x41 是一个字节,它们根本不相等。

一旦你在这一点上得到启发,你就可以毫无困难地解决你的问题。您只需决定软件中的哪个组件为这些字节值采用 ASCII 编码,以及如何更改该行为或确保出现不同的字节值。

PS:短语“扩展 ASCII”和“ANSI 字符集”用词不当。

于 2011-07-27T23:03:01.837 回答
3

尝试

## -*- 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

于 2011-07-27T20:03:08.757 回答
1

尝试用批判的眼光检查您的数据:

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 |令牌: |
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 |......]+(|

粗体字的东西是两批(每个字节从 0xc0 到 0xff 都包括在内)。您似乎有一个二进制文件(可能是已编译正则表达式的转储),而不是文本文件。我建议您将其作为二进制文件阅读,而不是将其粘贴到您的 Python 源文件中。您还应该阅读 mako 文档以了解它的预期。

在查看转储的文本部分后更新:您很可能能够在纯 ASCII 正则表达式中表达这一点,例如,您将有一行包含

token: WORD "[A-Za-z0-9\xc0-\xff]+(etc)etc"
于 2011-07-28T02:11:14.497 回答