Альтернативы взгляду переменной ширины в регулярном выражении Python
Недавно я решил перейти к глубокому концу пула Python и начать преобразовывать часть моего кода R в Python, и я застрял на чем-то очень важном для меня. В своей работе я трачу много времени на анализ текстовых данных, которые, как мы все знаем, очень неструктурированы. В результате я стал полагаться на особенность регулярных выражений в regex, а функциональность обхода R довольно надежна. Например, если я анализирую PDF, который может вводить пробелы между буквами при распознавании файла, я получу желаемое значение примерно так:
oAcctNum <- str_extract(textBlock[indexVal], "(?<=ORIG\\s?:\\s?/\\s?)[A-Z0-9]+")
В Python это невозможно, потому что использование ?
делает взгляд за выражением переменной ширины в отличие от фиксированной ширины. Эта функциональность достаточно важна для меня, так что она удерживает меня от желания использовать Python, но вместо того, чтобы разочаровываться в языке, я хотел бы узнать, как Pythonista решает эту проблему. Должен ли я предварительно обработать строку перед извлечением текста? Что-то вроде этого:
oAcctNum = re.sub(r"(?<=\b\w)\s(?=\w\b)", "")
oAcctNum = re.search(r"(?<=ORIG:/)([A-Z0-9])", textBlock[indexVal]).group(1)
Есть ли более эффективный способ сделать это? Поскольку этот пример был тривиальным, эта проблема возникает очень сложным образом с данными, с которыми я работаю, и мне не хотелось бы выполнять такую предварительную обработку для каждой анализируемой строки текста.
Наконец, я прошу прощения, если это не то место, где можно задать этот вопрос; Я не был уверен, где еще разместить это. Заранее спасибо.
3 ответа
Вам нужно использовать группы захвата в этом случае вы описали:
"(?<=ORIG\\s?:\\s?/\\s?)[A-Z0-9]+"
станет
r"ORIG\s?:\s?/\s?([A-Z0-9]+)"
Значение будет в .group(1)
, Обратите внимание, что необработанные строки являются предпочтительными.
Вот пример кода:
import re
p = re.compile(r'ORIG\s?:\s?/\s?([A-Z0-9]+)', re.IGNORECASE)
test_str = "ORIG:/texthere"
print re.search(p, test_str).group(1)
Если вам не нужны перекрывающиеся совпадения, захват использования групп вместо просмотра довольно прост.
Обратите внимание, что если вы можете использовать группы, вам, как правило, не нужно смотреть назад. Так как насчет
match = re.search(r"ORIG\s?:\s?/\s?([A-Z0-9]+)", string)
if match:
text = match.group(1)
На практике:
>>> string = 'ORIG : / AB123'
>>> match = re.search(r"ORIG\s?:\s?/\s?([A-Z0-9]+)", string)
>>> match
<_sre.SRE_Match object; span=(0, 12), match='ORIG : / AB123'>
>>> match.group(1)
'AB123'
print re.findall(r"ORIG\s?:\s?/\s?([A-Z0-9]+)",test_str)
Вы можете напрямую использовать findall
который вернет все группы в регулярном выражении, если таковые имеются.