此问题在此处已有答案:
Why order matters in this RegEx with alternation?(3个答案)
上个月关门了。
JavaDoc for java.util.regex.Matcher.find()
说:
尝试查找与模式匹配的输入序列的下一个子序列。
该方法从匹配器区域的开始处开始,或者,如果该方法的先前调用成功并且匹配器此后未被重置,则从先前匹配未匹配的第一个字符处开始。
如果匹配成功,则可以通过start、end和group方法获得更多信息。
这不是它实际上做的。在玩了一会儿之后,我对它实际上是做什么有了一些直觉,但我想知道是否在任何地方都有记录。
一些例子:
Pattern.compile("a|ad").matcher("ad").find() --> group() = "a"
Pattern.compile("ad|a").matcher("ad").find() --> group() = "ad"
字符串
显然,子序列a
匹配两个模式,但第二个匹配器跳过a
并发现ad
是“匹配模式的下一个子序列”。
类似地,我认为我们都同意[abc]+
匹配单个a
、b
或c
,但是
Pattern.compile("[abc]+").matcher("ababab").find() --> group = "ababab"
型
这跳过了a
是该图案的完美精细匹配的事实。
我认为,如果实现是基于模式的,那么它正在以某种顺序尝试模式的各个部分。因此,a|ad
匹配a
并忽略d
,但ad|a
则相反。[abc]+
贪婪地匹配,即使它正在寻找下一个子序列匹配。
所以问题是,JavaDoc应该说什么?它不是匹配的最长子序列(参见a
vs ad
),也不是匹配的第一个子序列(参见ababab
vs a
)。那么,这个方法实际上是在做什么呢?有没有一种方法可以将它固定到一个合理的规范中呢?
请注意,我理解这里发生的事情。我只是指出这个方法的行为与JavaDoc * 和 * 不匹配,如果不明确地描述这个方法的实现,就不清楚如何修复JavaDoc。find
没有找到“下一个与模式匹配的子序列”。它不仅根据匹配模式的字符串,而且还根据模式的构造方式来查找匹配模式的下一个子序列。
2条答案
按热度按时间mum43rcc1#
Java的正则表达式使用backtracking实现,因此给定像
x|y
这样的模式,它将首先尝试匹配x
,如果失败,则重置并尝试y
。因此,顺序很重要。对于第一个例子,
a
和ad
都至少部分匹配字符串"ad"
,因此无论哪个模式首先被赋予or运算符,都会被发现为匹配。对于第二个例子,
+
是一个贪婪的量词,所以它会尝试尽可能多地匹配。在这种情况下,整个字符串都匹配。为了尽可能少地匹配,应该使用不情愿的+?
,它只匹配一个"a"
。这个特定的
Matcher
方法的文档没有解释所有这些关于正则表达式的细节,但它并不是不正确的。wkftcu5l2#
显然,子序列a匹配两个模式,但是第二个匹配器跳过
a
并找到ad
作为“匹配模式的下一个子序列”。..."*它没有跳过 a,因为模式首先指定了 ad。
a
vsad
)..."*它将是输入的最长子序列,而不是模式。
正则表达式引擎将尝试匹配第一个提供的模式,而不是两个模式中最短的模式。
[abc]+
匹配单个a
,b
或c
,但是...这跳过了a
是该图案的完美精细匹配的事实。..."*+
指定它应该尽可能多地匹配。你可以附加一个
?
,[abc]+?
。这将导致它只匹配 a,然后匹配 B,依此类推。我猜他们是在推断这一点。我发现大多数技术写作都有某种无意的推断上下文。
当然,你可以向公司询问这件事。我相信他们会很感激你的通知。
从本质上讲,正则表达式引擎是非常简单的,它只是从左到右工作,在一个循环内。
我建议阅读关于 regex 的 Wikipedia 文章,它涵盖了所有这些主题。