Регулярное выражение для следования шаблону, кроме фигурных скобок - PullRequest
0 голосов
/ 26 мая 2020

Мне сложно придумать чистое регулярное выражение (в реализации Javascript), которое будет захватывать столько строк, сколько может следовать шаблону, но все, что внутри фигурных скобок, не должно соответствовать шаблону. Я не уверен, что лучший способ объяснить это, кроме как на примере:

Например: предположим, что шаблон таков, что строка должна начинаться с 0, заканчиваться где угодно, но разрешать только последовательность 1, 2 или 3 между ними, поэтому я использую ^(0[123]+0). Это должно соответствовать первой части строк:


    <b>0213123123130</b>
    <b>01231231231230</b>3123123
    <b>01231230</b>123123031230
    etc.

Но я хочу иметь возможность вставлять {gibberish} между фигурными скобками в строку, и регулярное выражение позволяет ему нарушать шаблон. т.е. игнорировать узор фигурных скобок и все, что внутри, но по-прежнему захватывать всю строку, включая {gibberish}. Таким образом, все будет выделено жирным шрифтом:


    <b>01232231{whatever 3 gArBaGe? I want.}121{foo}2310</b>312{bar}3120123

, а 0 внутри фигурных скобок не завершит захват преждевременно, даже если шаблон правильный.


    <b>01213123123123{21310030123012301}31231230</b>123

EDIT: Теперь, Я знаю, что мог бы просто сделать что-нибудь вроде ^0[123]*?(?:{.*})*?[123]*?0, может быть? Но это работает, только если есть один набор фигурных скобок, и теперь мне нужно продублировать свой шаблон [123]. По мере того, как этот шаблон [123] становится более сложным, то, что он появляется более одного раза в Regex, становится действительно непонятным. Что-то вроде лучшего трюка с регулярными выражениями казалось многообещающим, но я не мог понять, как его здесь применить. Использование сумасшедших поисков кажется единственным способом сейчас, но я надеюсь, что есть более чистый способ.

Ответы [ 4 ]

4 голосов
/ 26 мая 2020

Поскольку вы указали, что хотите, чтобы совпадение было полностью, включая мусор, вы можете использовать ^0([123]+(?:{[^}]*}[123]*)*)0 и использовать $ 1, чтобы получить часть между 0, или $ 0, чтобы получить все, что соответствует.

https://regex101.com/r/iFSabs/3

Вот краткое изложение того, как работает регулярное выражение:

  • ^ привязывает совпадение к началу строки
  • 0 соответствует буквальному нулевому символу
  • ([123]+(?:{[^}]*}[123]*)*) - это группа захвата, которая захватывает все, что находится внутри нее.
    • [123]+ соответствует одному или нескольким экземплярам 1, 2 или 3
    • (?:{[^}]*}[123]*)* - это группа без захвата. Т.е. он будет частью матча, но не будет содержать $ # для использования в качестве замены или совпадения.
      • {[^}]*} соответствует литералу {, за которым следует любое количество символов, отличных от }, за которым следует}
      • [123]* соответствует нулю или более экземплярам 1, 2 , или 3
      • Тогда вся эта группа без захвата может быть сопоставлена ​​0 или более раз.

Процесс, лежащий в основе это регулярное выражение называется развертыванием l oop. http://www.softec.lu/site/RegularExpressions/UnrollingTheLoop дает хорошее описание этого. (с несколькими исправлениями опечаток)

Метод развертывания l oop основан на гипотезе о том, что в большинстве случаев вы [знаете] в [повторяющемся] чередовании, что должно быть самый обычный и какой исключительный. Первый случай мы будем называть нормальным, а второй - частным. Общий синтаксис развертывания техники l oop может быть записан как:

normal * (специальный нормальный *) *

Что может означать что-то вроде соответствия нормальному случаю, если вы найдете особый случай, сопоставьте его, а затем снова сопоставите нормальный случай. [Вы] заметите, что часть этого синтаксиса может [потенциально] привести к суперлинейному совпадению.

Пример использования Regex # test и Regex # match:

const strings = [
  '0213123123130',
  '012312312312303123123',
  '01231230123123031230',
  '01213123123123{21310030123012301}31231230123',
  '01212121{hello 0}121312',
  '012321212211231{whatever 3 gArBaGe? I want.}1212313123120123',
  '012321212211231{whatever 3 gArBaGe? I want.}121231{extra garbage}3123120123',
];
const regex = /^0([123]+(?:{[^}]*}[123]*)*)0/

console.log('tests')
console.log(strings.map(string => `'${string}': ${regex.test(string)}`))


console.log('matches');
let matches = strings
  .map((string) => regex.exec(string))
  .map((match) => (match ? match[1] : undefined));
console.log(matches);

Ответ Robo Robok - это то место, где я бы go с, если вы хотите сохранить только часть без скобок, хотя с использованием немного другого регулярного выражения ({[^}]*}) для немного больше производительности.

1 голос
/ 26 мая 2020

Вы можете использовать

^0[123]*(?:{[^{}]*}[123]*)*0
  • ^ Начало строки
  • 0 Соответствует нулю
  • [123]* Соответствует 0+ раз либо 1, 2 или 3
  • (?: Группа без захвата
    • {[^{}]*}[123]* совпадение от открытия до закрытия }, за которым следует 0+ либо 1, 2 или 3
  • )* Закройте группу и повторите 0+ раз
  • 0 Соответствует нулю

Regex demo

1 голос
/ 26 мая 2020

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

^(0(?:[123]|{.+?})+0)

Это позволяет строку, начинающуюся с 0, а затем любую из ваши символы шаблона (1, 2 или 3), или один из разделов { gibberish }, и позволяет это повторять для обработки нескольких разделов gibberi sh, и, наконец, он должен заканчиваться 0.

https://regex101.com/r/K4teGY/2

1 голос
/ 26 мая 2020

А как насчет другого? Проверка строки с удаленными фигурными тегами:

const string = '012321212211231{whatever 3 gArBaGe? I want.}1212313123120123{foo}123';
const stringWithoutTags = string.replace(/\{.*?\}/g, '');

const result = /^(0[123]+0)/.test(stringWithoutTags);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...