2009-03-31 8 views
5

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

<a href="home.php" class="link" title="Home">Home</a> 
<a href="home.php" title="Home" class="link">Home</a> 

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

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

+0

Мне нравится @Josh Bush ответ ниже, так как это то, что работает для меня сейчас, когда я наткнулся на это – Rick

+0

Нет, вы не можете этого сделать. Это одна из причин, по которым вы ** не используете регулярные выражения для анализа HTML (или XML). Используйте подходящий модуль синтаксического анализа HTML. ** Вы не можете надежно проанализировать HTML с регулярными выражениями, и вы столкнетесь с печалью и разочарованием в будущем. Как только HTML изменится с ваших ожиданий, ваш код будет сломан. См. Http: // htmlparsing.com/php для примеров того, как правильно анализировать HTML с PHP-модулями, которые уже были написаны, протестированы и отлажены. –

+0

Это одна из многих причин, по которым регулярные выражения не подходят для синтаксического анализа XML или HTML. –

ответ

8

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

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

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

+2

Большинство HTML недействительны XML. Таким образом, вам действительно нужна библиотека разбора HTML. И в зависимости от того, почему вы пытаетесь извлечь эту информацию, она не может требовать написания приложения вокруг какой-либо библиотеки. Может быть, это просто одна вещь, где вы хотите получить некоторую грубую информацию. – Kibbee

+0

К сожалению, я думаю, что мне нужно взвесить значение возможности анализировать недействительный XML против смешного числа перестановок. В определенный момент регулярное выражение не будет таким тривиальным. Это не просто одноразовый проект, но я думаю, что мне придется использовать библиотеку. – VirtuosiMedia

+1

Несколько регулярных выражений не могут быть ужасной идеей, но лучше не делать все в одном. Во-первых, используйте регулярное выражение для получения информации внутри , затем используйте другую для извлечения элементов и т. Д. И обрабатывайте их соответственно. Это гораздо более читаемо и легче писать. –

0

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

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

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

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

+0

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

0

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

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

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

2

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

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

<a ((?<key>\w+)\s?=\s?['"](?<value>\w+)['"])+ /> 
+0

это, наверное, самое разумное решение, просто используя регулярное выражение (regex) вместо предварительно построенного парсера css) – Rick

-1

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

Допустим, вы хотите, чтобы соответствовать любой из этих шести строк:

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 = <<LINES 
123-abc-456-abc-789-abc-0AB 
123-abc-456-abc-789-def-0AB 
123-abc-456-abc-789-ghi-0AB 
123-abc-456-def-789-abc-0AB 
123-abc-456-def-789-def-0AB 
123-abc-456-def-789-ghi-0AB 
123-abc-456-ghi-789-abc-0AB 
123-abc-456-ghi-789-def-0AB 
123-abc-456-ghi-789-ghi-0AB 
123-def-456-abc-789-abc-0AB 
123-def-456-abc-789-def-0AB 
123-def-456-abc-789-ghi-0AB 
123-def-456-def-789-abc-0AB 
123-def-456-def-789-def-0AB 
123-def-456-def-789-ghi-0AB 
123-def-456-ghi-789-abc-0AB 
123-def-456-ghi-789-def-0AB 
123-def-456-ghi-789-ghi-0AB 
123-ghi-456-abc-789-abc-0AB 
123-ghi-456-abc-789-def-0AB 
123-ghi-456-abc-789-ghi-0AB 
123-ghi-456-def-789-abc-0AB 
123-ghi-456-def-789-def-0AB 
123-ghi-456-def-789-ghi-0AB 
123-ghi-456-ghi-789-abc-0AB 
123-ghi-456-ghi-789-def-0AB 
123-ghi-456-ghi-789-ghi-0AB 
LINES 

# outputs only the permutations 
puts input.grep(/123-(abc|def|ghi)-456-(?!\1)(abc|def|ghi)-789-(?!\1|\2)(abc|def|ghi)-0AB/) 

Для перестановки из пяти элементов, было бы:

/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 

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

/<a href="home.php" (class="link"|title="Home") (?!\1)(class="link"|title="Home")>Home<\/a>/ 
3

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

<a\b[^<>]*> 

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

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

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

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

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

5

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

//a[@class and @title] 

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

+0

Я использую немного xpath сейчас, хорошее предложение. – VirtuosiMedia

Смежные вопросы