#regex #pcre
#регулярное выражение #pcre
Вопрос:
Учитывая этот шаблон PCRE:
/(<name>[^<>]*</name>[^<>]*<phone>[^<>]*</phone>)/
И этот текст темы:
<name>John Stevens</name> <phone>888-555-1212</phone>
<name>Peter Wilson</name>
<phone>888-555-2424</phone>
Как я могу заставить регулярное выражение соответствовать первой паре имя-телефон, но не второй? Я не хочу сопоставлять пары, разделенные разрывами строк. Я попытался включить конец строки в класс отрицаемых символов вот так [^<>$]*
, но ничего не изменилось.
Вы можете использовать следующие онлайн-инструменты для тестирования ваших выражений:
http://rubular.com /
http://www.regextester.com /
Спасибо.
Комментарии:
1. Внутри символьного класса
$
теряет свое особое значение и становится просто буквальным знаком доллара. Что вы хотите, так это:[^<>rn]
как предлагает sawa.
Ответ №1:
Я думаю, это поможет
/<name>[^<>]*</name>[^<>rn]*<phone>[^<>]*</phone>/
Все, что вы помещаете в класс, [ ]
должно представлять собой один символ. $
интерпретируется как литерал $
внутри класса, вероятно, потому, что $
конец строки имеет ширину 0 и не может быть интерпретирован как таковой внутри класса. (Отредактировано после комментария ridgerunner)
Кстати, я снял круглые скобки, которые окружают ваше регулярное выражение, потому что все, что ему соответствует, может быть указано как полное совпадение.
Комментарии:
1. 1 (но
$
имеет эффект внутри класса char — он соответствует знаку доллара.)2. @ridgerunner Спасибо, что указали. Я исправлю свой ответ.
3. Я также добавил
r
, как указал ridgerunner. Я имел в виду только unix.
Ответ №2:
Если вы не хотите сопоставлять пары, разделенные разрывами строк, то следующее регулярное выражение выполнит эту работу:
/(<name>[^<>]*</name>.*?<phone>[^<>]*</phone>)/
Соответствует только имени, пара телефонов, поскольку точка .
не будет совпадать, EOL
но [^<>]
будет соответствовать ей.
Протестировал это на http://rubular.com/r/amXvq20sl8
Комментарии:
1. Спасибо. Но мне также нужно было исключить
<>
, чтобы предотвратить захват других тегов.2. На самом деле не помешало бы сделать это
[^<>]*
выше, однако я думаю, что как только мы уже окажемся внутри,<name>
тогда захватить все вплоть до</name>' we just need
[<] *`3. Верно, и мне нравится это изменение. Что я опустил из текста темы, так это то, что между именем и телефоном могут быть другие теги, которые я не хочу фиксировать, если они там есть. ie
<name>Mark</name><name>Bill</name><phone>888...</phone>
..*
Будет отображать оба имени в одной строке. Я знаю, что мог бы сделать его ленивым вместо жадного, но это может негативно повлиять на другие части моего шаблона. Я думаю, чтоrn
как указано выше, у меня сработает. С добавлением вашего изменения:[^<rn]
.
Ответ №3:
Эти сайты, похоже, не поддерживают весь синтаксис PCRE. Я использовал этот сайт:http://lumadis.be/regex/test_regex.php
И это сработало:
/^(<name>[^<>]*</name>[^<>$]*<phone>[^<>]*</phone>)/
/(?-s)(<name>[^<>]*</name>.*<phone>[^<>]*</phone>)/
вероятно, лучше