Почему регулярное выражение 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))
Другие вопросы по тегам