#regex #performance
#регулярное выражение #Производительность
Вопрос:
Итак, я придумал следующее регулярное выражение:
([^s\] (?:\.[^s\]*)*)(?:.*?)(S .phpb)
Тестовая ссылка: https://regex101.com/r/NV6Bk4/4
Он соответствует двоичному файлу и имени скрипта командной строки. Пример:
php --strict myscript.php --arg=value
соответствует php
и myscript.php
в группе (1) и группе (2).
Проблема в этой части в середине: (?:.*?)
, это приводит к комбинаторному взрыву, замедляя регулярное выражение для больших входных данных. Есть ли способ оптимизировать это? Поскольку нет никакой закономерности, я ничего не могу придумать.
Чтобы уточнить, правило, которому я пытаюсь соответствовать, таково: сопоставьте любой путь к команде, возможно, содержащий экранированные пробелы. Игнорируйте любые аргументы, следующие за ним. Сопоставьте файл, заканчивающийся на .php, игнорируйте все, что следует за ним. Команда должна быть в группе (1), имя файла должно быть в группе (2).
Комментарии:
1. В какой среде вы запускаете регулярное выражение?
2. На самом деле, гораздо важнее знать настоящие правила. Что сопоставляется и почему? Проблема очевидна: последующие смежные шаблоны могут соответствовать одному и тому же типу символов.
3. Он будет работать в Java 8.
4. Проверьте
^([^s\]* (?:\.[^s\]*)*).*?(S .phpb)
, посмотрите демонстрацию . Если ваши совпадения начинаются с начала строки, используйте^
и используйте притяжательный квантификатор с первым отрицаемым символьным классом5. Это выглядит многообещающе! Есть ли способ сделать это
match()
? К сожалению, это ограничение, которое у меня есть.
Ответ №1:
Вы можете использовать следующее «исправление» с Matcher#matches()
:
([^s\]* (?:\.[^s\]*)*).*?(S .phpb).*
В Java
String regex = "([^\s\\]* (?:\\.[^\s\\]*)*).*?(\S \.php\b).*";
Смотрите демонстрацию регулярных выражений. Обратите внимание, что литерал .
вне символьного класса должен быть экранирован. Скомпилируйте шаблон с Pattern.DOTALL
помощью if, если строка может иметь разрывы строк.
Как вы видите, .*?
часть соответствует любому символу, и (?:\.[^s\]*)*
прежде чем она сможет соответствовать любым 0 или более символам (так что это своего рода необязательно), и следующий смежный шаблон .*?
слева [^s\]
— это тот, который может соответствовать тем же символам, .*?
что и . Это означает, что механизм регулярных выражений может вернуться к первому подшаблону, и это создает множество способов сопоставления строки, обычно называемых катастрофическим возвратом.
Если вы запретите возврат к первому классу отрицаемых символов с *
притяжательным квантификатором, он уже будет работать намного надежнее.
Добавьте .*
в конце, чтобы заставить его работать .matches()
, так как этот метод требует полного совпадения строк.
Комментарии:
1. Спасибо за объяснение. Выдающийся!