Regex для вложенных атрибутов XML
Допустим, у меня есть следующая строка:
"<aa v={<dd>sop</dd>} z={ <bb y={ <cc x={st}>ABC</cc> }></bb> }></aa>"
Как я могу написать регулярное выражение общего назначения (изменение имен тегов, изменение имен атрибутов) для соответствия содержимого внутри {}
, или <dd>sop</dd>
или же <bb y={ <cc x={st}>ABC</cc> }></bb>
,
Regex я написал "(\s*\w*=\s*\{)\s*(<.*>)\s*(\})"
Матчи
"<dd>sop</dd>} z={ <bb y={ <cc x={st}>ABC</cc> }></bb>"
что не правильно.
2 ответа
В универсальном регулярном выражении нет способа хорошо справиться со вложением. Отсюда и все преимущества, когда возникает такой вопрос - никогда не используйте регулярные выражения для разбора XML/HTML.
В некоторых простых случаях это может быть выгодно, хотя. Если, как и в вашем примере, количество вложенных уровней ограничено, вы можете просто добавить одно регулярное выражение для каждого уровня.
Теперь давайте сделаем это по шагам. Для обработки первого не вложенного атрибута вы можете использовать
{[^}]*}
Это соответствует начальной скобке, за которой следует любое число, кроме закрывающей скобки, за которой следует закрывающая скобка. Для простоты я собираюсь поместить сердце этого в не захватывающую группу, как
{(?:[^}])*}
Это потому, что при вставке альтернативных, это необходимо.
Если вы теперь допускаете для этого что- нибудь, кроме закрывающей скобки ([^}]
) также быть еще одним вложенным уровнем скобок и просто присоединиться к первому регулярному выражению, например
{(?:{[^}]*}|[^}])*}
^^^^^^^ original regex inserted as alternative (to it self)
это позволяет для одного уровня вложенности. Делая то же самое снова, присоединяясь к этому регулярному выражению в качестве альтернативы себе, как
{(?:{(?:{[^}]*}|[^}])*}|{[^}]*}|[^}])*}
^^^^^^^^^^^^^^^ previous level repeated
позволит на другой уровень вложенности. При желании это можно повторить для большего количества уровней.
Это не обрабатывает захват имен атрибутов и прочее, хотя, потому что ваш вопрос не совсем ясен относительно того, что вы хотите там, но он показывает вам один из способов (imo самый простой для понимания, или...:P) для обработки вложенность в регулярных выражениях.
Вы можете увидеть, как он обрабатывает ваш пример здесь, на regex101.
С уважением
Вы пытаетесь бороться со сбалансированным набором брекетов. Это требует рекурсивных регулярных выражений. По определению, рекурсивные регулярные выражения не являются регулярными. Во всяком случае, некоторые языки поддерживают их, например, Perl, PHP, ruby. Это хороший учебник по теме.
Как правило, вы должны извлекать такую информацию с помощью полноценного парсера, такого как yacc.
Это регулярное выражение, которое может работать с несбалансированными скобками: ([ =]*)=(\{[^}]*\})
, Это будет соответствовать {<dd>sop</dd>}
а также {st}
что правильно. К сожалению, это будет соответствовать { <bb y={ <cc x={st}
тоже, что не совсем то, что вы хотите.