Работа с регулярными выражениями - повторяющиеся шаблоны - PullRequest
3 голосов
/ 28 октября 2011

Я пытаюсь использовать регулярные выражения для соответствия некоторому тексту.

Следующий пример - это то, что я пытаюсь собрать.

@Identifier('VariableA', 'VariableB', 'VariableX', ..., 'VariableZ')

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

\@(\w+)\W+(\w+)\W+(\w+)\W+(\w+)

Это захватывает идентификатор и до трех переменных.

Редактировать: это только я, или регулярные выражения не так мощны, как ясделать их? 1011 *

Ответы [ 4 ]

3 голосов
/ 28 октября 2011

Вы хотите использовать scan для такого рода вещей.Базовый шаблон будет выглядеть так:

s.scan(/\w+/)

Это даст вам массив всех последовательных последовательностей для символов слова:

>> "@Identifier('VariableA', 'VariableB', 'VariableX', 'VariableZ')".scan(/\w+/)
=> ["Identifier", "VariableA", "VariableB", "VariableX", "VariableZ"]

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

s.scan(/@(\w+)\(([^)]+?)\)/).map { |m| [ m.first, m.last.scan(/\w+/) ] }

Это даст вам массив массивов, каждый внутренний массив будет иметь часть «Идентификатор» в качестве первого элемента, а часть «Переменная»как массив во втором элементе.Например:

>> s = "pancakes @Identifier('VariableA', 'VariableB', 'VariableX', 'VariableZ') pancakes @Pancakes('one','two','three') eggs"
>> s.scan(/@(\w+)\(([^)]+?)\)/).map { |m| [ m.first, m.last.scan(/\w+/) ] }
=> [["Identifier", ["VariableA", "VariableB", "VariableX", "VariableZ"]], ["Pancakes", ["one", "two", "three"]]]

Если вы можете столкнуться с экранированными кавычками внутри битов "Variable", тогда вам понадобится нечто более сложное.


Некоторые примечания к выражению:

@            # A literal "@".
(            # Open a group
  \w+        # One more more ("+") word characters ("\w").
)            # Close the group.
\(           # A literal "(", parentheses are used for group so we escape it.
(            # Open a group.
  [          # Open a character class.
    ^)       # The "^" at the beginning of a [] means "not", the ")" isn't escaped because it doesn't have any special meaning inside a character class.
  ]          # Close a character class.
  +?         # One more of the preceding pattern but don't be greedy.
)            # Close the group.
\)           # A literal ")".

Вам на самом деле не нужно [^)]+? здесь, просто [^)]+ подойдет, но я использую не жадные формы по привычке, потому что обычно это то, что я имею в виду.Группировка используется для разделения частей @Identifier и Variable, чтобы мы могли легко получить желаемый вывод вложенного массива.

0 голосов
/ 28 октября 2011

Вы можете использовать просто (\w+).

С учетом входной строки @Identifier('VariableA', 'VariableB', 'VariableX', 'VariableZ')

Результаты будут такими:

  1. Identifier
  2. VariableA
  3. VariableB
  4. VariableX
  5. VariableZ

Это будет работать для произвольного числа переменных.

Для дальнейшего использованияЛегко и весело поиграть с идеями регулярных выражений на Rubular .

0 голосов
/ 28 октября 2011

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

Я не знаю, поддерживает ли Ruby это или нет, но я уверен, что .NET и новый PERL 6 поддерживают это.

В вашем случае вы можете использовать два регулярных выражения. Один для захвата идентификатора, например ^\s*@(\w+)

и еще один для захвата всех переменных, например result = subject.scan(/'[^']+'/)

0 голосов
/ 28 октября 2011

Но Алекс думает, что ты имел в виду, что хотел запечатлеть одно и то же четыре раза. Если вы хотите захватить один и тот же шаблон, но разные вещи, то вы можете рассмотреть две вещи:

итерация. В perl можно сказать

while ($variable =~ /regex/g) {

'g' обозначает 'global' и означает, что каждый раз, когда вызывается регулярное выражение, оно соответствует / next / instance.

Другой вариант - рекурсия. Напишите свое регулярное выражение так:

/(what you want)(.*)/

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

...