(Python) Как проверить длинную строку для нескольких регулярных выражений? - PullRequest
2 голосов
/ 15 апреля 2020

Я хочу убедиться, что длинная строка может совпадать с несколькими регулярными выражениями одновременно.

У меня есть длинная многострочная строка, содержащая список файлов и некоторое содержимое файла.

DIR1\FILE1.EXT1 CONTENT11
DIR1\FILE1.EXT1 CONTENT12
DIR1\FILE1.EXT1 CONTENT13
DIR1\FILE2.EXT1 CONTENT21
DIR2\FILE3.EXT2 CONTENT31
DIR3\FILE3.EXT2 CONTENT11

Список обычно содержит сотни тысяч строк, иногда несколько миллионов.

Я хочу проверить, что список содержит предопределенные пары файл / контент:

FILE1 CONTENT11
FILE1 CONTENT12
FILE3 CONTENT11

Я знаю, что я можно проверить, что строка содержит все эти пары, сопоставив строку с некоторыми регулярными выражениями

"^\S*FILE1\S*\tCONTENT11$"
"^\S*FILE1\S*\tCONTENT12$"
"^\S*FILE3\S*\tCONTENT11$"
import re

def all_matching(str, rxs):
    res = True
    for rx in rxs:
        p = re.compile(rx, re.M)
        res = res and p.search(str)
    return(res)

input1 = """DIR1\\FILE1.EXT1\tCONTENT11
DIR1\\FILE1.EXT1\tCONTENT12
DIR1\\FILE1.EXT1\tCONTENT13
DIR1\\FILE2.EXT1\tCONTENT21
DIR2\\FILE3.EXT2\tCONTENT31
DIR3\\FILE3.EXT2\tCONTENT11"""

input2 = """DIR1\\FILE1.EXT1\tCONTENT11
DIR1\\FILE1.EXT1\tCONTENT12
DIR1\\FILE1.EXT1\tCONTENT13
DIR1\\FILE2.EXT1\tCONTENT21
DIR2\\FILE3.EXT2\tCONTENT31"""

rxs = [r"^\S*FILE1\S*\tCONTENT11$",r"^\S*FILE1\S*\tCONTENT12$",r"^\S*FILE3\S*\tCONTENT11$"]

if all_matching(input1,rxs):
    print("input1 matches all rxs") # excpected
else:
    print("input1 do not match all rxs")

if all_matching(input2,rxs):
    print("input2 matches all rxs")
else:
    print("input2 do not match all rxs") # expected because input2 doesn't match wirh rxs[2]

ideone доступен здесь

Однако, как входные данные В моем случае строка очень длинная, я бы предпочел не запускать поиск много раз ...
Мне кажется, что можно изменить таким образом функцию all_matching.

Любая помощь будет очень признателен!

EDIT

прояснил проблему предоставленный образец кода

1 Ответ

2 голосов
/ 15 апреля 2020

Вы можете построить одно регулярное выражение из имеющихся у вас строк регулярного выражения, для которого потребуется найти все регулярные выражения для поиска совпадения во входной строке.

Полученное регулярное выражение будет выглядеть как

\A(?=(?:.*\n)*?\S*FILE1\S*\tCONTENT11$)(?=(?:.*\n)*?\S*FILE1\S*\tCONTENT12$)(?=(?:.*\n)*?\S*FILE3\S*\tCONTENT11$)

См. regex demo .

По сути, оно будет соответствовать:

  • (?m) - re.M / re.MULTILINE опция встроенного флага
  • \A - начало строки (не начало строки!), Все указатели ниже будут запускаться один за другим, проверяя строку с самого начала, пока один из них не завершится неудачей
  • (?=(?:.*\n)*?\S*FILE1\S*\tCONTENT11$) - положительный прогноз, который, непосредственно справа от текущего местоположения, требует присутствия
    • (?:.*\n)*? - 0 или более (но как можно меньше, шаблон будет пробоваться, только если последующий подшаблоны не совпадают)
    • \S* - 0+ непробельные символы
    • FILE1 - строка
    • \S* - 0+ непробельные символы
    • \tCONTENT11 - табуляция и CONTENT11 подстрока
    • $ - конец строки (поскольку (?m) позволяет $ соответствовать e ая строк)
  • (?=(?:.*\n)*?\S*FILE1\S*\tCONTENT12$) - заголовок, работающий аналогично предыдущему, требующий FILE1 и CONTENT12 подстрок в строке
  • (?=(?:.*\n)*?\S*FILE3\S*\tCONTENT11$) - заголовок, работающий аналогично предыдущему, требующий подстрок FILE3 и CONTENT11 в строке.

В Python он будет выглядеть как

rxs = [r"^\S*FILE1\S*\tCONTENT11$",r"^\S*FILE1\S*\tCONTENT12$",r"^\S*FILE3\S*\tCONTENT11$"]
pat = re.compile( r"(?m)\A(?=(?:.*\n)*?{})".format(r")(?=(?:.*\n)*?".join([rx[1:] for rx in rxs])) )

Тогда метод проверки будет выглядеть так:

def all_matching(s, pat):
    return pat.search(s)

См. full Python demo online .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...