Ruby 正则表达式在哪个位置失败?
我需要一个非常简单的字符串验证器,它将显示第一个符号与所需格式不对应的位置。我想使用正则表达式,但在这种情况下,我必须找到字符串与表达式相对应的停止位置,而我找不到一个可以这样做的方法。 (这一定是一个相当简单的方法……也许没有?) 例如,如果我有正则表达式:Ruby 正则表达式在哪个位置失败?,ruby,regex,string,syntax,substring,Ruby,Regex,String,Syntax,Substring,我需要一个非常简单的字符串验证器,它将显示第一个符号与所需格式不对应的位置。我想使用正则表达式,但在这种情况下,我必须找到字符串与表达式相对应的停止位置,而我找不到一个可以这样做的方法。 (这一定是一个相当简单的方法……也许没有?) 例如,如果我有正则表达式: /^Q+E+R+$/ 带字符串: "QQQQEEE2ER" 期望的结果应该是7这是一个有趣的任务,可以通过一个整洁的正则表达式技巧来完成: ^(?:(?=(Q+)))?(?:(?=(Q+E+)))?(?:(?=(Q+E+R+)))?(
/^Q+E+R+$/
带字符串:
"QQQQEEE2ER"
期望的结果应该是7这是一个有趣的任务,可以通过一个整洁的正则表达式技巧来完成:
^(?:(?=(Q+)))?(?:(?=(Q+E+)))?(?:(?=(Q+E+R+)))?(?:(?=(Q+E+R+$)))?
我们有四个可选的lookahead检查模式的各个部分,并以增量方式捕获组1、2、3和4的部分匹配
Q+
,如果可以匹配,在您的示例中为qqq
Q+E+
,如果可以匹配,在您的示例中为EEE
Q+E+R+
,如果可以匹配,在您的示例中为nil
Q+E+R+$
如果可以匹配,在您的示例中为nil
设置的最后一个组$1.无?
,$2.无?
等
最后一组为您提供了可匹配的长度,因此在您的示例中,$2.length
为您提供了所需的7
顺便说一句,组2是最后一组的事实也告诉您,我们在
R+
上失败了一个想法:您可以做的是标记您的模式,并使用可选的嵌套捕获组编写它:
^(Q+(E+(R+($)?)?)?)?
然后,您只需要计算获得的捕获组的数量,就可以知道正则表达式引擎在模式中的停止位置,并且您可以使用整个匹配长度确定字符串中匹配结束的偏移量
正如@zx81在他的评论中所注意到的,如果其中一个元素可以匹配下一个元素(例如Q可以匹配元素E),那么情况就不同了
假设Q是\w
(并且可以匹配E和R)。对于字符串qqeerr
当^(\w+(E+)(R+)$
将给出三个组时,先前的模式将只给出一个捕获组(贪婪的\w+
匹配所有组):qqee
,E
,RRR
要获得相同的结果,您需要添加一个备选方案:
^((?:\w+(?=E)|\w+)(E+(R+($)?)?)?)?
在替代方案中,必须首先测试E存在的情况,并且只有当该分支失败(使用前瞻)时,才使用E不存在的另一个分支
因此,可以像这样重写完整模式,以处理此特定情况:
^((?:Q+(?=E)|Q+)((?:E+(?=R)|E+)((?:R+(?=$)|R+)($)?)?)?)?
也许你也可以看看gem。举个例子,你可以做以下几点 代码 将您的正则表达式更改为:
/^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\u matched\u chars(str)=str.size
示例
nbr_matched_chars("QQQQEEE2ER") #=> 7
nbr_matched_chars("QQQQEEEERR") #=> 10 (= "QQQQEEEERR".size)
nbr_matched_chars("QQAQQEEEER") #=> 2
解释
要了解这[显然:-)]起作用的原因,我们可以查看调用的结果,然后是:
就我个人而言,我希望有办法创建一个Regexp对象,然后让它“尝试并匹配”一个字符串,然后让它在第一次找不到匹配项时录制。这听起来像是一种“通用”的方式,因为正则表达式引擎可能知道它什么时候失败,尽管我正在阅读,而且看起来即使这样也可能不是一种可靠的优化方法<代码>/^(Q+(E+(R+($)?)?)?/。匹配('QQEE2ER')[0]。长度给出OP正在查找的
7
。如果它返回的值等于测试字符串的长度,则匹配成功。谢谢,但是手工构建模式可能有点苛刻,几乎不可能从原始模式自动构建模式。@JackWatson:我理解你的问题,但在这种情况下,您只需检查是否存在必须与@匹配的捕获组。稍后可以提取长度。请记住,此模式始终匹配任何字符串。@CasimimiritHippolyte再看一次,现在我觉得您的解决方案在测试Q+E+R+
中的标记时非常好,但如果标记不是互斥的,例如^(\w+(E+(R+($)?)?)?
,则会出现故障,正如你所知,这是一种常见的情况。在QER
,Q
,QE
等上,这表明只设置了一个组,而实际上^\w+E+R+
的所有令牌都参与了匹配。在这种情况下,我的解决方案仍然有效,因此在我看来,它可能更一般。虽然我会记住你的相互排斥的情况。你觉得怎么样?@Casimirithippolyte有点像黑客(我相信你会同意的),但就是这样,干得好。:)我花了很长时间才看完你的答案(+1),但我还没看完。你看,我快速浏览了你的个人资料,决定看看你在SO最糟糕(哈!)和最好的回答经历,现在我已经完成了一部分…@CarySwoveland哈,我也喜欢阅读别人的帖子。:)
nbr_matched_chars("QQQQEEE2ER") #=> 7
nbr_matched_chars("QQQQEEEERR") #=> 10 (= "QQQQEEEERR".size)
nbr_matched_chars("QQAQQEEEER") #=> 2
"QQQQEEE2ER".scan(r).flatten #=> ["QQQQ", "EEE" , nil ]
"QQQQEEEERR".scan(r).flatten #=> ["QQQQ", "EEEE", "RR"]
"QQAQQEEEER".scan(r).flatten #=> ["QQ" , nil , nil ]