Несколько совпадений в группе регулярных выражений?

Мне нужно сопоставить все теги (например,% thisIsATag%), которые встречаются в атрибутах XML. (Примечание. Я гарантированно получаю действительный XML, поэтому нет необходимости использовать полный обход DOM). Мое регулярное выражение работает, за исключением случаев, когда в одном атрибуте есть два тега, возвращается только последний.

Другими словами, это регулярное выражение должно найти tag1, tag2, …, tag6. Однако он опускает tag2 и tag5.

Вот вам интересная небольшая тестовая упряжь для вас (PHP):

<?php $xml = <<<XML <data> <slideshow width="625" height="250"> <screen delay="%tag1%"> <text x="30%" y="50%" animatefromx="800"> <line fontsize="32" fontstyle="bold" text="Screen One!%tag2% %tag3%"/> </text> </screen> <screen delay='%tag4%'> <text x="30%" y="50%" animatefromx="800"> <line fontsize='32' fontstyle='bold' text='Screen 2!%tag5%%tag6%'/> </text> </screen> <screen> <text x="30%" y="50%" animatefromx="800"> <line fontsize="32" fontstyle="bold" text="Screen Tres!"/> </text> </screen> <screen> <text x="30%" y="50%" animatefromx="800"> <line fontsize="32" fontstyle="bold" text="Screen FOURRRR!"/> </text> </screen> </slideshow> </data> XML; $matches = null; preg_match_all('#<[^>]+("([^%>"]*%([^%>"]+)%[^%>"]*)+"|\'([^%>\']*%([^%>\']+)%[^%>\']*)+\')[^>]*>#i', $xml, $matches); print_r($matches); ?> 

Благодаря! 🙂

То, что вы пытаетесь сделать, – это восстановление промежуточных захватов из групп, которые соответствуют более одного раза для каждого регулярного выражения. Насколько я знаю, только .NET и Perl 6 предоставляют эту возможность. Вам нужно будет выполнить эту работу в два этапа: сопоставить значение атрибута с одним или несколькими %tag% последовательностей в нем, а затем разбить отдельные последовательности.

Кажется, вам не нравится какой XML-тег или атрибут, с которыми связаны значения, поэтому вы можете использовать это несколько упрощенное выражение для поиска значений с помощью %tag% последовательностей в них:

 '#"([^"%<>]*+%[^%"]++%[^"]*+)"|\'([^\'%<>]*+%[^%\']++%[^\']*+)\'#' 

EDIT: это регулярное выражение фиксирует значение атрибута в группе 1 или группе 2, в зависимости от того, какие кавычки он использовал. Вот еще одна версия, которая объединяет альтернативы, поэтому она всегда может сохранить значение в группе 2:

 '#(["\'])((?:(?![%<>]|\1).)*+%(?:(?!%|\1).)++%(?:(?!\1).)*+)\1#' 

Это:

 (%[a-zA-Z0-9]+%) 

недостаточно? В вашем примере теги не отображаются нигде вне значений атрибутов – не так ли?

% \ w +% было бы еще более простым способом сделать это.