正则表达式在哪个位置失败?

时间:2014-06-02 18:46:29

标签: ruby regex string syntax substring

我需要一个非常简单的字符串验证器,它会显示第一个符号与所需格式不对应的位置。我想使用正则表达式,但在这种情况下,我必须找到字符串停止对应表达式的地方,我无法找到一个方法来做到这一点。 (它必须是一个相当简单的方法......也许没有一个?)

例如,如果我有正则表达式:

/^Q+E+R+$/

字符串:

"QQQQEEE2ER"

期望的结果应为7

3 个答案:

答案 0 :(得分:5)

一个想法:你可以做的是标记你的模式并用可选的嵌套捕获组写它:

^(Q+(E+(R+($)?)?)?)?

然后,您只需要计算获得的捕获组的数量,以了解正则表达式引擎在模式中停止的位置,并且可以确定字符串中匹配结尾与整个匹配长度的偏移量。

正如@ zx81在他的评论中注意到的那样,如果其中一个元素可以匹配下一个元素(例子Q可以匹配元素E),那么事情会变得不同。

假设Q是\w(并且可以匹配E和R)。对于字符串QQQEEERRR,当\w+将提供三个组时,先前模式将只提供一个捕获组(贪婪的^(\w+)(E+)(R+)$匹配所有):QQQEEERRR

要获得相同的结果,您需要添加更改:

^((?:\w+(?=E)|\w+)(E+(R+($)?)?)?)?

在交替中,必须首先测试E存在的情况,并且只有当该分支失败时(使用超前),才使用E不存在的另一个分支。

因此,可以像这样重写完整模式来处理这种特定情况:

^((?:Q+(?=E)|Q+)((?:E+(?=R)|E+)((?:R+(?=$)|R+)($)?)?)?)?

也许你可以看一下gem amatch

答案 1 :(得分:2)

这是一个有趣的任务,可以用一个简洁的正则表达式技巧来完成:

^(?:(?=(Q+)))?(?:(?=(Q+E+)))?(?:(?=(Q+E+R+)))?(?:(?=(Q+E+R+$)))?

我们有四个可选的前瞻,检查模式的各个部分,并逐步捕获到第1,2,3和4组的部分匹配。

  1. 如果可以匹配,则第1组包含Q+,例如QQQQ
  2. 第2组包含Q+E+(如果可以匹配),在您的示例EEE中。
  3. 如果可以匹配,则第3组包含Q+E+R+,例如nil
  4. 如果可以匹配,则第3组包含Q+E+R+$,例如nil
  5. 在您的代码中,检查通过测试!$1.nil?!$2.nil?等设置的最后一个组。

    最后一组为您提供了可匹配的长度,因此在您的示例中,$2.length会为您提供所需的7

    顺便说一下,第2组是最后一组的事实也告诉你我们在R+失败了。

答案 2 :(得分:2)

对于您的示例,您可以执行以下操作。

<强>代码

从以下位置更改正则表达式:

    /^Q+E+R+$/

R = /^(Q*)(E*)(R*)/

然后将以下方法应用于字符串:

def nbr_matched_chars(str)
   str.scan(R).flatten.reduce(0) {|t,e| return t if e.nil?; t+e.size } 
end
当且仅当str

时,

nbr_matched_chars(str) == str.size才匹配原始正则表达式

<强>实施例

nbr_matched_chars("QQQQEEE2ER") #=>  7
nbr_matched_chars("QQQQEEEERR") #=> 10 (= "QQQQEEEERR".size)
nbr_matched_chars("QQAQQEEEER") #=>  2

<强>解释

要了解为什么[显然:-)]有效,我们可以查看调用String#scan的结果,然后是Array#flatten

"QQQQEEE2ER".scan(r).flatten #=> ["QQQQ", "EEE" , nil ]
"QQQQEEEERR".scan(r).flatten #=> ["QQQQ", "EEEE", "RR"]
"QQAQQEEEER".scan(r).flatten #=> ["QQ"  , nil   , nil ]