Регулярное выражение проблемы - PullRequest
0 голосов
/ 02 ноября 2009

Привет, ребята, я вырываю волосы, пытаясь создать регулярное выражение, похожее на:

{TextOrNumber{MoreTextOrNumber}} 

Обратите внимание на соответствующий номер открытия / закрытия {}. Это вообще возможно?

Большое спасибо.

Ответы [ 4 ]

2 голосов
/ 02 ноября 2009

Обратите внимание на соответствующий номер открытия / закрытия {}. Это вообще возможно?

Исторически, нет. Однако современные регулярные выражения на самом деле не регулярные , а некоторые допускают такие конструкции:

\{TextOrNumber(?R)?\}

(?R) рекурсивно вставляет шаблон снова . Обратите внимание, что не все движки регулярных выражений поддерживают это (пока).

0 голосов
/ 02 ноября 2009

Не просто, но возможно

Официально регулярные выражения не предназначены для разбора вложенных парных скобок - и если вы попытаетесь это сделать, вы столкнетесь со всевозможными проблемами. Есть другие другие инструменты (такие как генераторы синтаксических анализаторов, например, yacc или bison), которые разработаны для таких структур и могут хорошо с ними справляться. Но это может быть сделано - и если вы все сделаете правильно, это может быть даже проще, чем грамматика yacc со всем кодом поддержки, чтобы обойти проблемы yacc.

Вот несколько подсказок:

Прежде всего, мои предложения работают лучше всего, если у вас есть символы, которые никогда не появятся на входе. Часто такие символы, как \ 01 и \ 02, никогда не должны появляться, поэтому вы можете сделать

s/[\01\02]/ /g; 

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

s/([\01\02%])/"%".ord($1)/ge;

Обратите внимание, что я также избежал escape-символа "%".

Теперь я предлагаю разобрать скобки изнутри : заменить любую подстроку "{text}", где "text" содержит , а не содержит какие-либо квадратные скобки вместо заполнителя "\ 01 $ number \ 2 "и сохраните включенный текст в массиве $ [$ number]:

$number=1;
while (s/\{([^{}]*)\}/"\01$number\02"/e) { $array[$number]=$1; $number++; }
$array[0]=$_;  # $array[0] corresponds to your input

В качестве последнего шага вы можете захотеть обработать каждый элемент в @array, чтобы вытащить и обработать маркеры "\ 01 $ number \ 02". Это легко, потому что они больше не являются вложенными.

Я с радостью использую эту идею в нескольких синтаксических анализаторах (включая разделение совпадающих типов скобок, таких как "() {} []" и т. Д.).

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

0 голосов
/ 02 ноября 2009

Если вам нужно сделать произвольное количество фигурных скобок, вы можете использовать генератор синтаксического анализатора или создать регулярное выражение во вложенной функции. Ниже приведен пример рекурсивного регулярного выражения в ruby.

def parse(s)
  if s =~ /^\{([A-Za-z0-9]*)({.*})?\}$/ then
    puts $1
    parse($2)
  end
end

parse("{foo{bar{baz}}}")
0 голосов
/ 02 ноября 2009

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

/\{[a-z0-9]+([a-z0-9\{\}]+)?\}/i

перехватите «MoreTextOrNumber» и дайте ему снова совпадать, пока вы не закончите или он не даст сбой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...