Как я могу получить коллекцию значений из вложенных HTML-подобных элементов, используя RegExp? - PullRequest
1 голос
/ 04 декабря 2008

У меня проблема с созданием регулярного выражения для следующей задачи:

Предположим, у нас есть HTML-подобный текст:

<x>...<y>a</y>...<y>b</y>...</x>

Я хочу получить коллекцию значений внутри тегов <y></y>, расположенных внутри данного тега <x>, поэтому результатом приведенного выше примера будет набор из двух элементов ["a", "b"].

Кроме того, мы знаем, что:

  • <y> теги нельзя заключать в другие <y> теги
  • ... может включать любой текст или другие теги.

Как мне добиться этого с помощью RegExp?

Ответы [ 4 ]

9 голосов
/ 04 декабря 2008

Это задание для анализатора HTML / XML . Вы могли бы делать это с помощью регулярных выражений, но это было бы очень грязно. На странице, на которую я ссылаюсь, есть примеры.

3 голосов
/ 04 декабря 2008

Даю слово на этом:

"y" tags cannot be enclosed in other "y" tags

input looks like: <x>...<y>a</y>...<y>b</y>...</x>

и тот факт, что все остальное также не вложено и правильно отформатировано. (Отказ от ответственности: если это не так, это не моя вина.)

Во-первых, найдите содержимое любых тегов X с циклом на совпадения:

<x[^>]*>(.*?)</x>

Затем (в теле цикла) найдите любые теги Y в группе соответствия 1 «внешнего» соответствия сверху:

<y[^>]*>(.*?)</y>

Псевдо-код:

input = "<x>...<y>a</y>...<y>b</y>...</x>"
x_re  = "<x[^>]*>(.*?)</x>"
y_re  = "<y[^>]*>(.*?)</y>"

for each x_match in input.match_all(x_re)
  for each y_match in x_match.group(1).value.match_all(y_re)
    print y_match.group(1).value
  next y_match
next x_match

Псевдо-выход:

a
b

Дальнейшие разъяснения в комментариях показали, что в любом элементе X содержится произвольное количество элементов Y. Это означает, что не может быть ни одного регулярного выражения, которое соответствует им и извлекает их содержимое.

1 голос
/ 04 декабря 2008

Коротко и просто: используйте XPath:)

0 голосов
/ 05 декабря 2008

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

String str = "<y>c</y>...<x>...<y>a</y>...<y>b</y>...</x>...<y>d</y>";
String regex = "<y[^>]*+>(?=(?:[^<]++|<(?!/?+x\\b))*+</x>)(.*?)</y>";
Matcher m = Pattern.compile(regex).matcher(str);
while (m.find())
{
  System.out.println(m.group(1));
}

После того, как я сопоставил <y>, я использую прогноз, чтобы подтвердить, что где-то впереди есть </x>, но между текущей позицией и ней нет <x>. Предполагая, что псевдо-HTML достаточно хорошо сформирован, это означает, что текущая позиция совпадения находится внутри элемента "x".

Я интенсивно использовал притяжательные квантификаторы, потому что они делают такие вещи намного проще, но, как вы можете видеть, регулярное выражение все еще немного монстр. Помимо Java, единственными известными мне разновидностями регулярных выражений, поддерживающими квантификаторы поддержки, являются PHP и инструменты JGS (RegexBuddy / PowerGrep / EditPad Pro). С другой стороны, многие языки предоставляют способ получить все совпадения одновременно, но в Java мне пришлось написать свой собственный цикл для этого.

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

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