获得唯一的正则表达式匹配器结果(不使用地图或列表)
问题内容:
有没有办法只获得唯一的匹配?匹配后不使用列表或地图,我希望匹配器输出立即是唯一的。
样本输入/输出:
String input = "This is a question from [userName] about finding unique regex matches for [inputString] without using any lists or maps. -[userName].";
Pattern pattern = Pattern.compile("\\[[^\\[\\]]*\\]");
Matcher matcher = pattern.matcher(rawText);
while (matcher.find()) {
String tokenName = matcher.group(0);
System.out.println(tokenName);
}
这将输出以下内容:
[userName]
[inputString]
[userName]
但我希望它输出以下内容:
[userName]
[inputString]
问题答案:
就在这里。您可以结合使用否定的前瞻和反向引用:
"(\\[[^\\[\\]]*\\])(?!.*\\1)"
只有在您的实际模式匹配的字符串中不再出现该字符串时,该字符串才会匹配。有效地,这意味着您总是获得每个匹配项的 最后一次
出现,因此您将以不同的顺序获得它们:
[inputString]
[userName]
如果订购对您来说是个问题(例如,对于首次订购时至关重要),您将无法仅使用正则表达式来完成。为此,您需要后面的可变长度外观,而Java不支持。
进一步阅读:
关于一般解决方案的一些注意事项
请注意,这将适用于匹配宽度为非零的任何模式。通用解决方案很简单:
(yourPatternHere)(?!.*\1)
(我省略了双反斜杠,因为这仅适用于几种语言。)
如果您希望它与宽度为零的模式一起使用(因为您只想知道某个位置,并且仅出于某种原因而使用环视),则可以执行以下操作:
(zeroWidthPatternHere)(?!.+\1)
另外,请注意(通常),如果输入中可能包含换行符,则可能必须使用“单行”或“
dotall”选项(否则,超前仅会检查当前行)。如果您不能或不想激活它(因为您有一个包含不匹配换行符的句点的模式;或者因为您使用了JavaScript),这是一般的解决方案:
(yourPatternHere)(?![\s\S]*\1)
为了使该答案更广泛地适用,这里是如何仅匹配每个匹配项的 第 一个匹配项(在具有可变长度后视功能的引擎(如.NET)中)的方法:
(yourPatternHere)(?<!\1.*\1)
or
(yourPatternHere)(?<!\1[\s\S]*\1)