Как исключить разрыв строки из символьного класса регулярных выражений?

#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>)/
  

вероятно, лучше