Можно ли сократить регулярное выражение в соответствии? - PullRequest
0 голосов
/ 03 августа 2009

У меня есть несколько регулярных выражений, которые работают с очень длинными строками. Тем не менее, единственная часть строки, которая касается RE, находится в начале. Большинство RE похожи на:

\\s+?(\\w+?).*

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

Примечание. Приложение с RE написано с использованием классов java.regex.

Редактировать: Например, у меня есть следующее RE:

.*?id="number"[^>]*?>([^<]+?).*

Используется для больших файлов HTML, которые хранятся как StringBuilder s. Тег с id="number" всегда находится рядом с началом файла HTML.

Ответы [ 6 ]

6 голосов
/ 03 августа 2009

При использовании классов java.util.regex существует несколько способов сопоставления с данной строкой. Matcher.matches всегда соответствует входной строке целом . Matcher.find ищет что-то, совпадающее с вашим регулярным выражением где-то внутри входной строки. Наконец, Matcher.lookingAt сопоставляет ваше регулярное выражение с началом вашей входной строки.

Если вы используете Matcher.matches, вам может потребоваться .* в конце, чтобы соответствовать всей строке. Тем не менее, вам может быть лучше использовать один из других методов, который позволит вам отказаться от .*. Похоже, что Matcher.lookingAt может подойти для ваших целей.

2 голосов
/ 03 августа 2009

Почему бы просто не достать . *, вам это не нужно.

^\\s+?(\\w+?)
1 голос
/ 03 августа 2009
.*?id="number"[^>]*?>([^<]+?).*

Это действительно регулярное выражение, которое вы используете? Я спрашиваю, потому что ([^<]+?) всегда будет соответствовать ровно одному символу, как если бы вы написали ([^<]). Квантор + должен совпадать хотя бы один раз, но из-за нежелания немедленно переходить к следующей части - .* - которая всегда успешна. Удаление .* и переключение на find() или lookingAt() также не изменит это поведение (хотя, вероятно, будет немного быстрее получить тот же результат). Если вы хотите сопоставить весь текст до следующей угловой скобки, вам следует избавиться от знака вопроса: ([^<]+).

[^>]*?> тоже не имеет особого смысла. Вы должны потреблять столько не скобок, сколько есть, прежде чем вы сможете сопоставить скобки, так какой смысл делать этот квантификатор неохотным? На самом деле, нет смысла делать его жадным; если [^>]* соответствует как можно большему количеству символов, а следующий символ не равен '>', то вы знаете, что возврат не поможет. Вы также можете использовать квантификатор притяжений - [^>]*+> - или атомарную группу - (?>[^>]*+)> - если их поддерживает регулярное выражение.

Первая количественная часть - .*? - единственная, которая используется правильно (если не оптимально). Помещение в начало регулярного выражения имитирует поведение find(), когда вы используете lookingAt() или (с .* в конце) matches(). Однако, как вы обнаружили, отключение и использование find() более эффективно.

Неохотные квантификаторы очень удобны, но в последнее время кажется, что они становятся переэкспонированными. Все чаще и чаще я вижу людей, которые дают советы «Используйте неохотные квантификаторы» без объяснения причин или квалификации - просто еще одна серебряная пуля. И я полагаю, что такие регулярные выражения, как в этом вопросе, являются результатом. Из трех неохотных квантификаторов один должен был быть жадным, один должен был быть собственником, а другой вообще не должен был там быть.

РЕДАКТИРОВАТЬ: Вот пример, чтобы проиллюстрировать некоторые из того, о чем я говорю, и ответить на комментарий Стивена С. Учитывая эту строку:

<div id="number" class="whatever">abc123</div>

... динамические части регулярного выражения совпадают так:

.*?         => '<div '

[^>]*?      => ' class="whatever"'

([^<]+?)    => 'a'

.*          => 'bc123</div>'

Изменение всех неохотных квантификаторов на жадные не меняет общее совпадение (всю строку) и не меняет того, что сопоставляется первым двум динамическим частям. Но последние два перераспределяются:

([^<]+)     => 'abc123'

.*          => '</div>'

Глядя на оригинальное регулярное выражение, я подумал, что это должен быть желаемый результат; зачем использовать такое сложное подвыражение внутри группы захвата, если не захватывать весь контент, 'abc123'? Вот что заставляет меня верить, что неохотные квантификаторы использовались вслепую как панацея.

Еще одна вещь: оглядываясь назад, я вижу, что ОП на самом деле не говорит , он удалил .*? из передней части регулярного выражения, когда он переключился на метод find() , @ Бен, если ты этого не сделал, ты должен; сейчас все просто замедляется. Это оставило бы вас с этим регулярным выражением:

id="number"[^>]*+>([^<]+)

Я тоже не хочу, чтобы кто-то думал, что я оспариваю принятый ответ. Я просто чешу этот зуд, который у меня есть из-за чрезмерного / неправильного использования неохотных квантификаторов.

0 голосов
/ 03 августа 2009

В данном конкретном случае простым ответом было использование «найти», а не «совпадений». Но если это не сработает, класс Java Pattern поддерживает регулярные выражения с так называемыми собственническими квантификаторами, которые можно использовать для предотвращения обратного отслеживания.

Притяжательные квантификаторы - третья альтернатива жадным и неохотным квантификаторам. Синтаксис в Java: «X? +» Или «X * +» или «X ++». Притяжательные квантификаторы соответствуют как можно большему количеству символов (например, жадные квантификаторы), но если остальная часть шаблона не соответствует, притяжательный квантификатор завершается неудачей, вместо того, чтобы отступать. (Вроде как «разрез» в Прологе.)

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

Учебную информацию о квантификаторах притяжения можно найти на этой странице .

0 голосов
/ 03 августа 2009

Есть отличная библиотека для работы с HTML-файлами, в том числе плохо сформированными, реальными: BeautifulSoup http://www.crummy.com/software/BeautifulSoup/

Было бы очень легко найти тэг id = с этой библиотекой

0 голосов
/ 03 августа 2009

Если вы имеете дело с HTML, регулярные выражения не являются подходящим инструментом для анализа, если у вас нет 100% контроля над файлами данных. Это в конечном итоге сломается.

Мне кажется, вам нужно содержимое тега с id = "number" и, очевидно, больше. Существуют удобные парсеры, позволяющие преобразовывать XSLT при вводе HTML, что может быть именно тем, что вам нужно. Я посмотрю, если вам интересно.

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