Синтаксис регулярного выражения с переменным порядком

Есть ли способ указать, что две или несколько фраз регулярных выражений могут возникать в любом порядке? Например, атрибуты XML могут быть записаны в любом порядке. Скажем, что у меня есть следующий XML:

Home Home 

Как мне написать совпадение, проверяющее class и заголовок, и работает для обоих случаев? Я в основном ищу синтаксис, который позволяет мне проверять любой порядок, а не просто соответствовать classу и названию, как я могу это сделать. Есть ли какой-либо способ, помимо включения обеих комбинаций и подключения их к «|»?

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

Нет, я считаю, что лучший способ сделать это с помощью одного RE – это точно так же, как вы описываете. К сожалению, это будет очень грязно, когда ваш XML может иметь 5 разных атрибутов, что дает вам большое количество различных RE для проверки.

С другой стороны, я бы не делал этого с RE вообще, поскольку они не предназначены для программирования языков. Что случилось с старомодным подходом к использованию библиотеки обработки XML?

Если вам нужно использовать RE, этот ответ, вероятно, не поможет, но я верю в использование правильных инструментов для работы.

Вы считали xpath? (где порядок атрибутов не имеет значения)

 //a[@class and @title] 

Выберете оба узла качестве действительных совпадений. Единственное предостережение в том, что вход должен быть xhtml (хорошо сформированный xml).

Вы можете создать lookahead для каждого из атрибутов и подключить их к регулярному выражению для всего тега. Например, регулярное выражение для тега может быть

 ]*> 

Если вы используете это на XML, вам, вероятно, понадобится нечто более сложное. Само по себе это базовое регулярное выражение будет соответствовать тегу с нулевым или большим количеством атрибутов. Затем вы добавляете lookhead для каждого из атрибутов, которые вы хотите сопоставить:

 (?=[^<>]*\s+class="link") (?=[^<>]*\s+title="Home") 

[^<>]* Позволяет сканировать вперед для атрибута, но не позволит ему смотреть за пределы скобки угла закрытия. Сопоставление ведущих пробелов здесь в lookahead служит двум целям: оно более гибко, чем сопоставление в базовом регулярном выражении, и гарантирует, что мы сопоставим имя всего атрибута. Объединяя их, мы получаем:

 ]*\s+class="link")(?=[^<>]*\s+title="Home")[^<>]+>[^<>]+ 

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

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

Что-то вроде этого (непроверенный, используя синтаксис regex .net с символами \ w для слов и \ s для пробелов):

 \w+)\s?=\s?['"](?\w+)['"])+ /> 

Первым специальным решением может быть следующее.

 ((class|title)="[^"]*?" *)+ 

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

Самый простой способ – написать регулярное выражение, которое подхватит часть , а затем напишет еще два регулярных выражения, чтобы вытащить class и заголовок. Хотя вы, вероятно, могли бы сделать это с помощью одного регулярного выражения, это было бы очень сложно и, вероятно, гораздо более подвержено ошибкам.

С одним регулярным выражением вам нужно что-то вроде

 ]*((class="([^"]*)")|(title="([^"]*)"))?((title="([^"]*)")|(class="([^"]*)"))?[^>]*> 

Это просто из первых рук, не проверяя, действительно ли это действительно. Гораздо проще просто разделить и преодолеть проблему.

Если вы хотите сопоставить перестановку набора элементов, вы можете использовать комбинацию обратных ссылок и нулевое отклонение в прямом направлении.

Скажем, вы хотите соответствовать любой из этих шести строк:

 123-abc-456-def-789-ghi-0AB 123-abc-456-ghi-789-def-0AB 123-def-456-abc-789-ghi-0AB 123-def-456-ghi-789-abc-0AB 123-ghi-456-abc-789-def-0AB 123-ghi-456-def-789-abc-0AB 

Вы можете сделать это со следующим регулярным выражением:

 /123-(abc|def|ghi)-456-(?!\1)(abc|def|ghi)-789-(?!\1|\2)(abc|def|ghi)-0AB/ 

Обратные ссылки ( \1 , \2 ) позволяют вам ссылаться на ваши предыдущие совпадения и сопоставлять ширину нулевой ширины ( (?!...) ), позволяя свести на нет позиционное совпадение, если они не совпадают, если совпадающие совпадения в этом положении. Объединяя два, убедитесь, что ваш матч является законной перестановкой данных элементов, причем каждая возможность возникает только один раз.

Так, например, в rubyе:

 input = <  

Для перестановки пяти элементов это будет:

 /1-(abc|def|ghi|jkl|mno)- 2-(?!\1)(abc|def|ghi|jkl|mno)- 3-(?!\1|\2)(abc|def|ghi|jkl|mno)- 4-(?!\1|\2|\3)(abc|def|ghi|jkl|mno)- 5-(?!\1|\2|\3|\4)(abc|def|ghi|jkl|mno)-6/x 

Для вашего примера регулярное выражение будет

 /Home< \/a>/