Почему регулярное выражение Python не соответствует (?=) Здесь?
Я пытаюсь получить информацию об авторе с сайта "pixiv". Код здесь с сайта:
<meta property="og:title" content="ラララ | かるは [pixiv]">
Я хочу получить это "かるは", и я использую регулярное выражение:
[\u0800-\u9fa5_a-zA-Z0-9_]+(?=\s\[pixiv\])
Тем не менее, в Python я не могу получить ничего взамен. (PS 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 ответа
Предполагая, что ваш код написан для Python 3, он работает правильно с Python 3.3 и выше и завершается ошибкой с тем же сообщением об ошибке для Python 3.2.x и ниже.
Решение
Самое простое решение - запустить ваш код на Python 3.3 или выше, и добавить защиту версии, чтобы предотвратить запуск кода на более низкой версии Python.
Второе решение заключается в использовании обычного строкового литерала Unicode, в котором escape-последовательности Unicode распознаются и обрабатываются. Недостаток этого метода заключается в том, что вы должны учитывать escape-последовательности и удваивать \
при необходимости, особенно в случае \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
, так как он также соответствует арабскому, деванагари, тайскому, лаосскому языку, рисованию коробки, символам и т. д.
объяснение
Escape-последовательности Юникода \u
а также \U
в необработанной строке Unicode
В Python 3 escape-последовательности в Юникоде \u
а также \U
не обрабатываются специально в необработанной строке Unicode, как указано в Python 3.0. Спецификация строкового литерала обновлена в Python 3.3, чтобы добавить u
префикс для более легкого обслуживания кода Python 2, но он не меняет поведения при разборе необработанной строки Unicode:
# 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, где escape-последовательности 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\])
Поддержка escape-последовательности Unicode \u
а также \U
в re
пакет
До Python 3.3, re
пакет не поддерживает \u
а также \U
Escape-последовательность Unicode, как видно из документации по Python 3.2. В следствии, \u
а также \U
интерпретируются как соответствующие литералы u
а также U
,
Добавление 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 наконец-то добавлена поддержка escape-последовательности Unicode в re
пакет, поэтому он работает правильно для последующих версий:
# 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
Исходный код работает правильно в Python 3. Однако u
Строковые префиксы требуются в Python 2:
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))