Мне нужно, чтобы python re совпадал, только если отсутствуют две строки и присутствуют две другие строки

#python #regex #re

#python #регулярное выражение #python-re

Вопрос:

Используя python 3.9.5, у меня есть эта строка

 >>> t
' LICENSE INVALIDn Your license does not include module AMS version 2020.103 on this machine.n Module AMSn LICENSE INVALIDn Module AMS version2020.103n Your license does not include module AMS version 2020.103 on this machine.n Module AMSn Module AMS version2020.103nLICENSE INVALIDnLICENSE INVALID'
 

Я хочу re, который вернет None, если найдена одна из строк ‘LICENSE INVALID’ или ‘лицензия не включает’; и, если обе эти строки отсутствуют и присутствуют обе строки ‘2020.103’ и ‘NORMAL TERMINATION’, только тогда я хочу, чтобы он возвращалсовпадение. (Если вообще ничего не совпадает, верните значение None .) Пока у меня есть

 >>> p=re.compile(r'^(?!.*LICENSE INVALID|license does not include).*(?:2020.103|NORMAL TERMINATION).*')
>>> print(p.search(s))
<re.Match object; span=(0, 8), match='2020.103'>
 

Это выполняет первую часть: возвращает None, если в тексте есть «НЕДЕЙСТВИТЕЛЬНАЯ ЛИЦЕНЗИЯ» или «лицензия не включена». Тем не менее, я считаю, что он выполняет исключительное совпадение «или» для последних двух строк. Я хочу, чтобы он выполнял «и». Это соответствует выше, когда я бы предпочел, чтобы этого не было. Вывод, который я сопоставляю, скорее всего, будет содержать ‘2020.103’ как при сбое (когда я не хочу, чтобы мой re нашел совпадение), так и при успехе (когда я хочу, чтобы мой re нашел совпадение). Мне нужно использовать re для этого, чтобы подогнать его к чужому коду, который я использую. Подводя итог: только если найдены ‘2020.103’ и ‘НОРМАЛЬНОЕ ЗАВЕРШЕНИЕ’, а ‘НЕДЕЙСТВИТЕЛЬНАЯ ЛИЦЕНЗИЯ’ и ‘лицензия не включает’ не найдены, не возвращайте значение None.

Ответ №1:

Я мог бы избежать регулярных выражений здесь и вместо этого использовать базовые строковые функции:

 inp = [' LICENSE INVALIDn Your license does not include module AMS version 2020.103 on this machine.n Module AMSn LICENSE INVALIDn Module AMS version2020.103n Your license does not include module AMS version 2020.103 on this machine.n Module AMSn Module AMS version2020.103nLICENSE INVALIDnLICENSE INVALID', 'Hello 2020.103 is NORMAL TERMINATION']

for x in inp:
    if "LICENSE INVALID" not in x and "license does not include" not in x and "2020.103" in x and "NORMAL TERMINATION" in x:
        print("MATCH: "   x)
    else:
        print("NO MATCH: "   x)
 

Только второй пример ввода в списке соответствует.

Ответ №2:

С регулярным выражением, не могли бы вы попробовать:

 p = re.compile(r'^(?!.*(?:LICENSE INVALID|license does not include)).*(?=.*2020.103)(?=.*NORMAL TERMINATION)')
 

Оно должно совпадать, если найдены ‘2020.103’ и ‘НОРМАЛЬНОЕ ЗАВЕРШЕНИЕ’, и ни один из ‘LICENSE INVALID’ и ‘license does not include’ не найдены.

Ответ №3:

Давайте проясним требования:

  • «вернуть нет, если найдена одна из строк «НЕДЕЙСТВИТЕЛЬНАЯ ЛИЦЕНЗИЯ» или «лицензия не включает»» означает, что вы хотите не выполнить сопоставление, если в строке присутствует любая из двух строк. Это тот случай, когда мы используем негативные (?!.*pattern1) прогнозы, , или где у нас есть два шаблона, мы используем (?!.*pattern1)(?!.*pattern2) или (?!.*(?:pattern1|pattern2)) , и так далее.
  • «присутствуют обе строки ‘2020.103’ и ‘НОРМАЛЬНОЕ ЗАВЕРШЕНИЕ’, только тогда я хочу, чтобы оно возвращало совпадение. (Если вообще ничего не совпадает, верните None тоже.)» означает, что вам нужно убедиться, что строка содержит два шаблона в любом порядке в строке, и это тот случай, когда мы используем ^(?=.*pattern1)(?=.*pattern2) .

Более того, вы заметили . в приведенных выше шаблонах. В Python re точка по умолчанию не соответствует символам разрыва строки, вам нужно использовать флаг re.S или re.DOTALL (или добавить (?s) в начале шаблона, чтобы переопределить поведение . во всем регулярном выражении, или использовать (?s:.) вместо . .

Итак, давайте объединим требования — сопоставим строку, которая содержит два шаблона в любом порядке, но не содержит ни одного шаблона или другого — в регулярное выражение:

 p=re.compile(r'^(?!.*b(?:LICENSE INVALID|license does not include)b)(?=.*(?<!d)2020.103(?!d))(?=.*bNORMAL TERMINATIONb).*', re.S)
 

Подробные сведения:

  • ^ — начало строки
  • (?!.*b(?:LICENSE INVALID|license does not include)b) — отрицательный прогноз, при котором совпадение не выполняется, если LICENSE INVALID license does not include где-либо после нуля или более символов есть либо или как целые слова, как можно больше
  • (?=.*(?<!d)2020.103(?!d)) — позитивный прогноз, требующий, чтобы a 2020.103 не предшествовал и не сопровождался цифрой где-либо после нуля или более символов, как можно больше
  • (?=.*bNORMAL TERMINATIONb) — положительный прогноз, требующий NORMAL TERMINATION целого слова в любом месте после нуля или более символов, как можно больше
  • .* — остальная часть строки. Не обязательно, если вам нужен логический результат. Смотрите демонстрацию Python:
 import re
s = ' LICENSE INVALIDn Your license does not include module AMS version 2020.103 on this machine.n Module AMSn LICENSE INVALIDn Module AMS version2020.103n Your license does not include module AMS version 2020.103 on this machine.n Module AMSn Module AMS version2020.103nLICENSE INVALIDnLICENSE INVALID'
p=re.compile(r'^(?!.*b(?:LICENSE INVALID|license does not include)b)(?=.*(?<!d)2020.103(?!d))(?=.*bNORMAL TERMINATIONb).*', re.S)
print(p.search(s)) # NO MATCH, there is "LICENSE INVALID" and even "license does not include", there is no expected "NORMAL TERMINATION", although there is "2020.103"
print(p.search('NORMAL TERMINATIONnBlah-blahn2020.103 code')) # MATCH, there are no "LICENSE INVALID" and "license does not include", there is "NORMAL TERMINATION" and "2020.103"
print(p.search('NORMAL TERMINATIONnBlah-blahn2020.1030 code')) # NO MATCH, same as above but "2020.1030" is not  "2020.103"