3

如果范围的一个或两个端点都在 BMP 之外,那么正则表达式中字符范围的预期语义到底是什么?我观察到以下输入在 Python 2.7 和 3.5 中的行为不同:

import re
bool(re.match(u"[\u1000-\U00021111]", "\u1234"))

在我的 2.7 中,我得到False了,在 3.5 中我得到了True。后者对我来说很有意义。前者可能是由于\U00021111由代理对表示\ud844\udd11,但即使那样我也不明白,因为\u1000-\ud844应该包含\u1234就好了。

  • 这是在某处指定的吗?
  • 这是预期的行为吗?
  • 这仅取决于 Python 版本,还是取决于有关 UTF-16 与 UTF-32 的编译时标志?
  • 有没有办法在不区分大小写的情况下获得一致的行为?
  • 如果区分大小写是不可避免的,那么条件是什么?
4

2 回答 2

3

Just use the u prefix with the input string to tell Python it is a Unicode string:

>>> bool(re.match(u"[\u1000-\U00021111]", u"\u1234")) # <= See u"\u1234"
True

In Python 2.7, you need to decode the strings to Unicode each time you process them. In Python 3, all strings are Unicode by default, and it is stated in the docs.

于 2016-04-21T08:15:06.317 回答
2

这是我到目前为止发现的。

Python 2.2 接受的PEP 261引入了一个编译时标志,以使用窄 UTF-16 表示或宽 UTF-32 字符表示来构建 unicode 支持。在运行时检查hex(sys.maxunicode)len(u'\U00012345')区分这些:窄构建将报告最大值0xffff和长度2,宽构建将报告最大值0x10ffff和长度1佩普 393Python 3.3 隐藏了 unicode 字符串的实现细节,使所有字符串看起来像 UTF-32(除非必要,否则实际上不会浪费那么多空间)。因此,在 3.3 之前的狭窄构建会将星体平面上的代码点分解为代理对,并独立处理各个代理,以构建正则表达式和要匹配的字符串。或者至少我找不到相反的迹象。

正如 Wiktor 指出的那样,我的示例非常愚蠢,因为我忘记了u第二个字符串文字的前缀。因此,Python 2 不会将其解析为转义序列,而是解析为字节字符串。这就解释了为什么即使在考虑了代理对之后,代码点似乎也不包含在该范围内。

至于预期的行为:从 Python 3.3 开始,基于构建类型的区别应该已经过时了。将每个代码点视为一个单元,无论平面如何,都应该是 Python 3 的前进方向。但是狭窄构建的向后兼容性对旧版本提出了一个相互矛盾的目标。

于 2016-04-27T09:14:53.770 回答