Как я могу извлечь переменное количество под-совпадений из регулярного выражения Ruby? - PullRequest
1 голос
/ 03 октября 2010

У меня есть несколько строк, которые я хотел бы сопоставить с образцом, а затем извлечь совпадения в виде переменных $ 1, $ 2 и т. Д.

У меня есть код сопоставления с образцом

a = /^([\+|\-]?[1-9]?)([C|P])(?:([\+|\-][1-9]?)([C|P]))*$/i.match(field)

ставит result = #{a.to_a.inspect}

С учетом вышеизложенного я могу легко сопоставить следующие примеры строк:

"C", "+ 2C", "2c-P", "2C-3P "," P + C "

И я подтвердил все эти работы на веб-сайте Rubular.
Однако, когда я пытаюсь сопоставить" + 2P-c-3p ",однако он соответствует «массивоподобному объекту» MatchData:

result = ["+2P-C-3P", "+2", "P", "-3", "P"]

Проблема в том, что я не могу извлечь в массив средний шаблон «-C».

То, что я ожидал бы увидеть, это:

result = ["+2P-C-3P", "+2", "P", "-", "C", "-3", "P"]

Кажется, что извлекается только конечная часть "-3P" как "-3" и "P"

Кто-нибудь знает, как я могу изменить свой шаблон для захвата средних матчей?
Так что в качестве другого примера, + 3c + 2p-c-4p, я ожидал бы создать:

["+3c+2p-c-4p", "+3", "C", "+2", "P", "-", "C", "-4", "P"]

но то, что я получаю это

["+3c+2p-c-4p", "+3", "C", "-4", "P"]

который комполностью пропускает среднюю часть.

Ответы [ 2 ]

4 голосов
/ 03 октября 2010

У вас есть глубокое (но распространенное) недопонимание того, как работают классы персонажей. Это:

[C|P]

неправильно. Если вы не хотите соответствовать трубе | символов. В классах персонажей чередования нет - они не похожи на группы. Это было бы правильно:

[CP]

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

^([+-]?\d?)([CP])(?:([+-]?\d?)([CP]))*$

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

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

Если группа совпадает несколько раз, будет сохранено только содержимое последнего совпадения. В Ruby нет способа получить содержимое предыдущих совпадений для этой группы.

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

1 голос
/ 03 октября 2010

Вот что мне удалось сделать:

([+-]?\d?)(C|P)(?=(?:[+-]?\d?[CP])*$)

Таким образом, вы захватываете несколько элементов.
Единственная проблема - правильность строки.Так как у ruby ​​нет заглядывания, я не могу проверить начало строки, поэтому zerhyju+2P-C-3P допустимо (но будет захватывать только +2P-C-3P), тогда как +2P-C-3Pzertyuio недействительно.

Если вы хотите захватить и проверить правильность вашей строки, лучший способ (IMO) - использовать два регулярных выражения, одно для проверки значения ^(?:[+-]?\d?[CP])*$, а второе для захвата ([+-]?\d?)(C|P) (вы также можете использовать ([CP]) для последней части).

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