2010-10-03 76 views
1

我有一些字符串,我想模式匹配,然后提取出的匹配,而变量$ 1,$ 2,等如何从Ruby正则表达式提取可变数量的子匹配?

模式匹配的代码,我是

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"] 

它完全忽略了中间环节。

+0

我删除了我的答案,因为我看到它不是很正确。我会在几分钟后处理并重新发布。 – ubiquibacon 2010-10-03 08:02:28

+0

谢谢。我试过了,没有,抱歉没有奏效。 – 2010-10-03 08:03:34

回答

1

这是我能够做到的:

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

这样你捕捉多个元素。
唯一的问题是字符串的有效性。由于红宝石没有外观,我不能检查字符串的开始,所以zerhyju+2P-C-3P是有效的(但只会捕获+2P-C-3P),而+2P-C-3Pzertyuio是无效的。

如果你想捕获和检查,如果你的字符串是有效的,最好的办法(IMO)是使用两个正则表达式,一个检查值^(?:[+-]?\d?[CP])*$和第二个捕获([+-]?\d?)(C|P)(您也可以使用([CP])为最后一部分)。

+0

我刚试过这个,它似乎在红宝石网站上工作。让我回顾一下你的答案。 “?=”是做什么的? – 2010-10-03 08:16:07

+0

+1使用两个正则表达式是我提出的分割和循环建议的另一种方法。不知道为什么你用'(?:C | P)'代替'[CP]'。 – Tomalak 2010-10-03 08:16:14

+0

@Tomalak,我没有真正想过。但是你是对的,用'[CP]'更清楚(它也被更新) – 2010-10-03 08:29:57

4

你对字符类的工作方式有着深刻的(但常见的)误解。此:

[C|P] 

是错误的。除非你想匹配管道|个字符。角色班没有变化 - 他们不像组。这将是正确的:

[CP] 

此外,还有在字符类没有元字符,所以你只需要逃跑很少的字符(即右方括号]和破折号-,除非你把它在组的结尾)。所以,你的正则表达式简化为:

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

你的第二个误解是,组数是动态的 - 你以某种方式有更多的群体中的结果,因为更多的比赛出现的字符串中。不是这种情况。

由于在正则表达式中有圆括号对,因此在结果中有完全一样多的组(当然少了非捕获组的数量)。在这种情况下,该数字是4.不多也不少。

如果一个组匹配多次,只保留上次匹配事件的内容。没有办法(在Ruby中)获取该组的先前匹配事件的内容。

作为一种替代方法,您可以将字符串正则分解为其有意义的部分,然后在循环中解析它们以提取所有信息。

+0

非常翔实。 – ubiquibacon 2010-10-03 08:09:43

+0

感谢您的意见Tomalek,让我检讨你的回应。新的模式匹配,所以原谅我[C | P]的误解。 – 2010-10-03 08:18:43