Использование условия в регулярных выражениях - PullRequest
0 голосов
/ 03 февраля 2009

Источник:

<TD>
    <A HREF="/home"><IMG SRC="/images/home.gif"></A>
    <IMG SRC="/images/spacer.gif">
    <A HREF="/search"><IMG SRC="/images/search.gif"></A>
    <IMG SRC="/images/spacer.gif">
    <A HREF="/help"><IMG SRC="/images/help.gif"></A>
</TD>

Regex:

  (<[Aa]\s+[^>]+>\s*)?<[Ii][Mm][Gg]\s+[^>]+>(?(1)\s*</[Aa]>)

Результат:

<A HREF="/home"><IMG SRC="/images/home.gif"></A>
<IMG SRC="/images/spacer.gif">
<A HREF="/search"><IMG SRC="/images/search.gif"></A>
<IMG SRC="/images/spacer.gif">
<A HREF="/help"><IMG SRC="/images/help.gif"></A>

что означает "? (1)"?

Когда я запускаю его на Java, это вызывает исключение: java.util.regex.PatternSyntaxException, «? (1)» не может быть распознан.

Объяснение в книге:

This pattern requires explanation. (<[Aa]\s+[^>]+>\s*)? matches an opening <A> or <a> tag (with any attributes that may be present), if present (the closing ? makes the expression optional). <[Ii][Mm][Gg]\s+[^>]+> then matches the <IMG> tag (regardless of case) with any of its attributes. (?(1)\s*</[Aa]>) starts off with a condition: ?(1) means execute only what comes next if backreference 1 (the opening <A> tag) exists (or in other words, execute only what comes next if the first <A> match was successful). If (1) exists, then \s*</[Aa]> matches any trailing whitespace followed by the closing </A> tag.

Ответы [ 4 ]

3 голосов
/ 03 февраля 2009

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

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

(?i)<a\s+[^>]+>\s*<img\s+[^>]+>\s*</a]>|<img\s+[^>]+>

Одним из преимуществ условной версии является то, что вы можете захватить тег IMG с помощью одной группы захвата:

(?i)(<a\s+[^>]+>\s*)?(<img\s+[^>]+>)(?(1)\s*</a>)

В альтернативной версии у вас должна быть группа захвата для каждой альтернативы, но это не так важно в Java, как в Perl, со всей его встроенной магией регулярных выражений. Вот как я мог бы извлечь теги IMG в Java:

Pattern p = Pattern.compile(
  "<a\\s+[^>]+>\\s*(<img\\s+[^>]+>)\\s*</a>|(<img\\s+[^>]+>)"
  Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(s);
while (m.find())
{
  System.out.println(m.start(1) != -1 ? m.group(1) : m.group(2));
}
3 голосов
/ 03 февраля 2009

Синтаксис правильный. Странно выглядящий (? ....) устанавливает условие. Это синтаксис регулярного выражения для оператора if ... then. (1) - это обратная ссылка на группу захвата в начале регулярного выражения, которая соответствует тегу html , если он есть, поскольку эта группа захвата является необязательной. Поскольку обратная ссылка на захваченный тег следует за частью регулярного выражения «если», то он проверяет, был ли захвачен открывающий тег , прежде чем пытаться сопоставить закрывающий тег. Довольно умный способ сделать оба тега необязательными, но использовать оба, когда существует первый. Таким образом, он может соответствовать всем строкам в тексте примера, хотя некоторые из них имеют только теги image.

Что касается того, почему в вашем случае возникает исключение, скорее всего, используемый вами тип регулярного выражения не поддерживает условные выражения. Не все так делают.

РЕДАКТИРОВАТЬ: Вот хорошая ссылка на условия в регулярных выражениях: http://www.regular -expressions.info / conditional.html

1 голос
/ 03 февраля 2009

Краткий ответ: это ничего не значит. Проблема заключается во всем этом фрагменте:

(?(1)\s*)

() создает обратную ссылку, поэтому вы можете повторно использовать любой текст внутри. Они также позволяют вам применять операторы ко всему внутри них (но в вашем примере это не сделано).

? означает, что элемент перед ним должен быть сопоставлен, если он есть, но он также в порядке, если это не так. Это просто не имеет смысла, когда появляется после (

(?: MoreTextHere ) Может использоваться для ускорения использования регулярных выражений, когда вам не нужно повторно использовать сопоставленный текст. Но это все еще не имеет смысла, зачем совпадать с 1, когда вы вводите HTML?

Попробуйте:

(?:<[Aa]\s+[^>]+>\s*)?<[Ii][Mm][Gg]\s+[^>]+>

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

1 голос
/ 03 февраля 2009

Может ли это быть группа без захвата, как описано здесь:

Существует также специальная группа, группа 0, который всегда представляет все выражение. Эта группа не входит в общем сообщается groupCount. Группы, начинающиеся с (? Чисты, не захватывающие группы, которые не захватывать текст и не рассчитывать на общая группа. (Вы увидите примеры не захватывающих групп позже в раздел Методы класса Pattern.)

Учебник по Java Regex

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