为什么python正则表达式在Linux上编译而不是Windows?

UsA*_*R33 10 python regex

我有一个正则表达式来检测unicode字符串中的无效xml 1.0字符:

bad_xml_chars = re.compile(u'[^\x09\x0A\x0D\u0020-\uD7FF\uE000-\uFFFD\U00010000-\U0010FFFF]', re.U)
Run Code Online (Sandbox Code Playgroud)

在Linux/python2.7上,这非常有效.在Windows上引发以下内容:

  File "C:\Python27\lib\re.py", line 190, in compile
    return _compile(pattern, flags)
  File "C:\Python27\lib\re.py", line 242, in _compile
    raise error, v # invalid expression
  sre_constants.error: bad character range
Run Code Online (Sandbox Code Playgroud)

任何想法为什么这不是在Windows上编译?

And*_*ark 16

您在Windows上有一个狭窄的Python构建,因此Unicode使用UTF-16.这意味着Unicode字符高于\uFFFFPython字符串中的两个单独字符.你应该看到这样的东西:

>>> len(u'\U00010000')
2
>>> u'\U00010000'[0]
u'\ud800'
>>> u'\U00010000'[1]
u'\udc00'
Run Code Online (Sandbox Code Playgroud)

以下是正则表达式引擎将如何尝试在窄版本上解释您的字符串:

[^\x09\x0A\x0D\u0020-\ud7ff\ue000-\ufffd\ud800\udc00-\udbff\udfff]
Run Code Online (Sandbox Code Playgroud)

您可以在此处看到\udc00-\udbff无效范围消息的来源.


int*_*jay 7

它不起作用,因为Windows版本的Python使用16位来表示unicode字符,编码为UTF-16.代码点10000及以上代表UTF-16中的两个代码单元,这会混淆re范围表示,该范围表示需要单个字符在其两侧-.

这是您传递给的字符串re.compile被拆分为字符的方式:

>>> [x for x in u'[^\x09\x0A\x0D\u0020-\uD7FF\uE000-\uFFFD\U00010000-\U0010FFFF]']
[u'[', u'^', u'\t', u'\n', u'\r', u' ', u'-', u'\ud7ff', u'\ue000', u'-', 
 u'\ufffd', u'\ud800', u'\udc00', u'-', u'\udbff', u'\udfff', u']']
Run Code Online (Sandbox Code Playgroud)

请注意,\U00010000-\U0010FFFF表示为5个字符:

u'\ud800', u'\udc00', u'-', u'\udbff', u'\udfff'
Run Code Online (Sandbox Code Playgroud)

里面的字符集[...],re.compile将此解释为字符u'\ud800'u'\udfff'和范围u'\udc00' - u'\udbff'.此范围无效,因为其结束小于其开始,这会导致错误.