perl -e '$_=join("", <>); m#<a.*?>.*?<.*?/a>#s; print "$&\n";'
Итак, хитрость в том, что весь ввод читается в $ _. Затем запускается стандартное /.../ регулярное выражение. Я использовал альтернативный синтаксис m # ... #, чтобы мне не пришлось использовать обратную косую черту "/", которые используются в xml. Наконец, постфикс «s» заставляет многострочные совпадения работать с помощью «.» также соответствует символу новой строки (обратите внимание также на опцию «m», которая меняет значения ^ и $). «$ &» - соответствующая строка. Это результат, который вы ищете. Если вам нужен только внутренний текст, вы можете заключить его в круглые скобки и вывести $ 1.
Я предполагаю, что вы подразумевали </a>
, а не /a>
как закрывающий разделитель xml.
Обратите внимание, что .*?
- это не жадная версия .*
, поэтому для <a>1</a><a>2</a>
она соответствует только <a>1</a>
.
Обратите внимание, что вложенные узлы могут вызывать проблемы, например <a><a></a></a>
. Это то же самое, что и при попытке сопоставить вложенные скобки "(", ")" или "{", "}". Это более интересная проблема. Регулярные выражения обычно не сохраняют состояния, поэтому сами по себе не поддерживают сохранение неограниченной глубины вложенности скобок. При программировании синтаксических анализаторов вы обычно используете регулярные выражения для низкоуровневого сопоставления строк и что-то еще для более высокого уровня парсинга токенов, например, bison. Есть грамматики бизонов для многих языков и, вероятно, для xml. xslt может быть даже лучше, но я не знаком с этим. Но для очень простого случая использования вы можете также обрабатывать вложенные блоки, например, в perl:
Вложенный код обработки скобок: (его можно легко адаптировать для обработки вложенных блоков XML)
$_ = "a{b{c}e}f";
my($level)=(1);
s/.*?({|})/$1/; # throw away everything before first match
while(/{|}/g) {
if($& eq "{") {
++$level;
} elsif($& eq "}") {
--$level;
if($level == 1) {
print "Result: ".$`.$&."\n";
$_=$'; # reset searchspace to after the match
last;
}
}
}
Result: {b{c}e}