重新匹配无:regex在Python实现中的差异?

ave*_*ird 3 python regex python-2.7

我在使用python regex库(re)匹配特定模式时遇到了一些麻烦。我正在尝试用数字(最多3个数字)匹配行,然后匹配单词集合(第一个单词和数字之间没有空格),这些单词正好由两个空格终止。括号中包含匹配字符串的一些示例:

test(58your own becoming )Adapted from Pyramid Text utterance 81.

(46ancestral fires )In Sumerian, a language recently supplanted by

(45lap of God )Ginzberg, Legends of the Bible, p. 1.

(9Island of the Egg )The symbolism of the cosmic egg is an integral aspect of almost every mythological tradition. In the

我正在使用以下表达式:

(\d+).+(  )
Run Code Online (Sandbox Code Playgroud)

相关的python代码如下:

# the search string is `tmp`
pattern = re.compile("(\d+).+(  )")
footnotes = pattern.finditer(tmp)
for footnote in footnotes:
    # do something with each match
Run Code Online (Sandbox Code Playgroud)

当我使用regexr这样的测试站点时,以上所有示例都完全符合预期。但是,python不匹配。有什么简单的我想念的吗?我也尝试过将表达式传递re为原始字符串。我似乎在文档中找不到其他可以尝试的东西。任何帮助将不胜感激!

编辑

完整的字符串可以在这里找到。

在这一点上,我相当确定它与我处理字符串的方式有关。如果我从文本文件中读取并执行以下代码,则输出为空:

with open("stone.md", "r+") as f:
    tmp = f.read()
    pattern = re.compile(r"(\d+).+  ")
    footnotes = pattern.finditer(tmp)
    for footnote in footnotes:
        print tmp[footnote.start():footnote.end()]
Run Code Online (Sandbox Code Playgroud)

但是,如果我运行:

tmp = """test58your own becoming  Adapted from Pyramid Text utterance 81."""
pattern = re.compile(r"(\d+).+  ")
footnotes = pattern.finditer(tmp)
for footnote in footnotes:
    print tmp[footnote.start():footnote.end()]
Run Code Online (Sandbox Code Playgroud)

我懂了 58your own becoming

Jos*_*RLi 5

您已成为Unicode象形文字的受害者。

您的正则表达式包含ASCII编码的空格字符(您习惯使用的常规空格)。但是,您要操作的全文包含不间断的空格,在HTML中为 和Unicode中U+00A0。在人眼看来,它看起来完全像一个常规空间,但它不是ASCII空间。

Python 3.6.2 (default, Jul 20 2017, 03:52:27) 
[GCC 7.1.1 20170630] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> '  '.encode('ascii')
b'  '
>>> '  '.encode('ascii')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
>>> '  '.encode('utf-8')
b'\xc2\xa0\xc2\xa0'
Run Code Online (Sandbox Code Playgroud)

以下正则表达式将为您提供所需的内容:

pattern = re.compile(b'(\d+).+(\xc2\xa0)'.decode('utf-8'))

这是在构造一个字节对象,然后将其解码为utf-8字符串,以便re可以使用它。

或者,甚至更好的是,您可以使用\s,它与您使用的正则表达式中的任何空格字符(覆盖Unicode)相匹配:

pattern = re.compile('(\d+).+(\s\s)')

那么,为什么答案中的正则表达式似乎起作用了?

因为浏览器将不间断空间呈现为ASCII空间,该空间会传播为浏览器复制粘贴缓冲区为ASCII空间。

一旦您公开了您正在使用的原始文本文件,我便能够发现这一点。我wget在URL上下载了带有的原始格式,该格式在原始文件中保留了Unicode空格,如果我将浏览器中的大文本文件复制粘贴到本地计算机上的文件中,那将不会发生。

哇。这是一个非常有趣的难题。谢谢你的问题。