为什么Python正则表达式与(?=)不匹配?

时间:2015-07-09 03:01:31

标签: python regex web-crawler

我正试图从网站上获取作者信息" pixiv"。代码来自网站:

<meta property="og:title" content="ラララ | かるは [pixiv]">

我想得到那个&#34;かるは&#34;我使用正则表达式:

[\u0800-\u9fa5_a-zA-Z0-9_]+(?=\s\[pixiv\])

然而,在Python中,我无法获得任何回报。 (P.S. websiteCode是该网站的源代码,我已经尝试将其打印出来并且它是正确的。具体来说,有

<meta property="og:title" content="ラララ | かるは [pixiv]">

里面):

这是我的Python代码:

authorPattern = re.compile(r'[\u0800-\u9fa5_a-zA-Z0-9_]+(?=\s\[pixiv\])')
tempAuthor = re.search(authorPattern, websiteCode)
print("temp: ", tempAuthor)

输出结果为:

Traceback (most recent call last):
  File "/Users/ChinYuer/Software-Engineering/Pixiv-Spider/pixiv.py", line 191, in <module>
    my.grab_image()
  File "/Users/ChinYuer/Software-Engineering/Pixiv-Spider/pixiv.py", line 84, in grab_image
    testAuthor = tempAuthor.group()
AttributeError: 'NoneType' object has no attribute 'group'

我在一些测试网站上尝试了我的正则表达式代码并且工作正常。

这真令人沮丧,如果有人能帮助我,我将非常感激。

再次感谢你!

2 个答案:

答案 0 :(得分:1)

假设您的代码是为Python 3编写的,它可以在Python 3.3及更高版本中正常运行,并且在Python 3.2.x及更低版本中出现相同的错误消息。

解决方案

最简单的解决方案是在Python 3.3或更高版本中运行您的代码,并添加version guard以防止较低版本的Python运行您的代码。

第二种解决方案是使用常规的Unicode字符串文字,其中识别和处理Unicode转义序列。这种方法的缺点是你必须要记住转义序列,并在必要时加倍\,特别是在\b的情况下,在它之前被解释为常规Unicode字符串文字中的退格字符。达到re.compile

# Python 3.2.5 (default, Jul 25 2014, 14:13:17)
>>> print('[\u0800-\u9fa5_a-zA-Z0-9_]+(?=\s\[pixiv\])')
[ࠀ-龥_a-zA-Z0-9_]+(?=\s\[pixiv\])

>>> import re
>>> re.compile('[\u0800-\u9fa5_a-zA-Z0-9_]+(?=\s\[pixiv\])', re.DEBUG)
max_repeat 1 4294967295
  in
    range (2048, 40869)
    literal 95
    range (97, 122)
    range (65, 90)
    range (48, 57)
    literal 95
assert 1
  in
    category category_space
  literal 91
  literal 112
  literal 105
  literal 120
  literal 105
  literal 118
  literal 93
<_sre.SRE_Pattern object at 0x6001fad70>

顺便说一句,您可能需要查看自己的角色范围\u0800-\u9fa5,因为它也符合Arabic, Devanagari, Thai, Lao, Box Drawing, Symbols etc.

解释

原始Unicode字符串

中的Unicode转义序列\u\U

在Python 3中,Unicode转义序列\u\U未在原始Unicode字符串中专门处理,如Python 3.0中所述。字符串文字的规范在Python 3.3中更新,以添加u前缀,以便更轻松地维护Python 2代码,但它doesn't change the parsing behavior for raw Unicode string

# Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 24 2015, 22:43:06) [MSC v.1600 32 bit (Intel)] on win32
>>> r'[\u8000]'
'[\\u8000]'
>>> '[\u8000]'
'[耀]'

这与Python 2相反,即使在原始Unicode字符串文字中,Unicode转义序列也会被处理为相应的Unicode字符:

# Python 2.7.8 (default, Jul 25 2014, 14:04:36)
>>> print(u'\u8000')
耀
>>> print(ur'\u8000')
耀

因此,问题中包含正则表达式的字符串,如Python 3中的正则表达式引擎所示:

>>> print(r'[\u0800-\u9fa5_a-zA-Z0-9_]+(?=\s\[pixiv\])')
[\u0800-\u9fa5_a-zA-Z0-9_]+(?=\s\[pixiv\])

支持\u包中的Unicode转义序列\Ure

在Python 3.3之前,re包不支持\u\U Unicode转义序列,如Python 3.2的文档中所示。因此,\u\U被解释为匹配文字uU

添加re.DEBUG标志,您可以看到编译的正则表达式的结果结构。为清晰起见,我注释了部分输出:

# Python 3.2.5 (default, Jul 25 2014, 14:13:17)
>>> import re
>>> re.compile(r'[\u0800-\u9fa5_a-zA-Z0-9_]+(?=\s\[pixiv\])', re.DEBUG)
max_repeat 1 4294967295
  in
    literal 117      # u (\u)
    literal 48       # 0
    literal 56       # 8
    literal 48       # 0
    range (48, 117)  # 0-u (0-\u)
    literal 57       # 9
    literal 102      # f
    literal 97       # a
    literal 53       # 5
    literal 95
    range (97, 122)
    range (65, 90)
    range (48, 57)
    literal 95
assert 1
  in
    category category_space
  literal 91
  literal 112
  literal 105
  literal 120
  literal 105
  literal 118
  literal 93
<_sre.SRE_Pattern object at 0x600178850>

Python 3.3最终在re包中添加了对Unicode转义序列的支持,因此它适用于后续版本:

# Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 24 2015, 22:43:06) [MSC v.1600 32 bit (Intel)] on win32
>>> re.compile(r'[\u0800-\u9fa5_a-zA-Z0-9_]+(?=\s\[pixiv\])', re.DEBUG);
max_repeat 1 2147483647
  in
    range (2048, 40869) # \u0800-\u9fa5
    literal 95
    range (97, 122)
    range (65, 90)
    range (48, 57)
    literal 95
assert 1
  in
    category category_space
  literal 91
  literal 112
  literal 105
  literal 120
  literal 105
  literal 118
  literal 93

答案 1 :(得分:0)

原始代码在Python 3中正常工作。但是,Python 2中需要u字符串前缀:

import re

websiteCode = u'<meta property="og:title" content="ラララ | かるは [pixiv]">'
authorPattern = re.compile(ur'[\u0800-\u9fa5_a-zA-Z0-9_]+(?=\s\[pixiv\])')
tempAuthor = re.search(authorPattern, websiteCode)
print(u"temp: " + tempAuthor.group(0))