仅匹配唯一的字符串出现次数

时间:2016-11-07 15:57:53

标签: regex

我们正在为电子邮件执行一些数据丢失防护,但问题是当人们多次回复电子邮件时,有时信用卡号或帐号会多次出现。

我们怎样才能让Java Regex只匹配一次字符串。

因此,例如,我们使用以下正则表达式来捕获匹配2个字母后跟5或6个数字的帐号。在任何一种情况下都会省略CR。

\b(?!CR)(?!cr)[A-Za-z]{2}[0-9]{5,6}\b

我们怎样才能找到它:

CX12345
CX14584
JB145888
JD748452
CX12345 (Ignore as its already found it above)
LM45855

2 个答案:

答案 0 :(得分:3)

唯一字符串出现可以与

匹配
<STRING_PATTERN>(?!.*<STRING_PATTERN>)  // Find the last occurrence
(?<!<STRING_PATTERN>.*)<STRING_PATTERN> // Find the first occurrence, only works in regex
                                        // that supports infinite-width lookbehind patterns

其中<STRING_PATTERN>是搜索其中唯一出现的模式。请注意,两者将与.NET正则表达式库一起使用,但是大多数其他库通常不支持第二个库(仅限PyPi Python regex库和JavaScript ECMAScript 2018正则表达式支持它)。请注意,.默认情况下与换行符不匹配,因此您需要传递一个类似DOTALL的修饰符(在大多数库中,您可以在模式中添加(?s)修饰符(仅在Ruby {{1}中) }执行相同的操作,或使用您传递给regex编译方法的特定标志。在How do I match any character across multiple lines in a regular expression?

中查看更多相关内容

你似乎需要这样的正则表达式:

(?m)

regex demo is available here

<强>详情:

  • /\b((?!CR|cr)[A-Za-z]{2}\d{5,6})\b(?![\s\S]*\b\1\b)/ - 领先的单词边界
  • \b - 第1组捕获
    • ((?!CR|cr)[A-Za-z]{2}\d{5,6}) - 接下来的两个字符不能是(?!CR|cr)CR,负面预测检查
    • cr - 2个ASCII字母
    • [A-Za-z]{2} - 5到6位
  • \d{5,6} - 尾随字边界
  • \b - 如果有任何0 +字符((?![\s\S]*\b\1\b))后面跟着一个字边界([\s\S]*),则匹配未通过的负面预测,相同的值被捕获到第1组(使用\b反向引用)和尾随字边界。

答案 1 :(得分:1)

我会在这里使用某种Map,以便记住你遇到的字符串。例如:

String ccNumber = "CX12345";
Map<String, Boolean> ccMap = new HashMap<>();

if (ccNumber.matches("^(?!CR)(?!cr)[A-Za-z]{2}[0-9]{5,6}$")) {
    ccMap.put(ccNumber, null);
}

然后迭代地图的键集,以获得与正则表达式中的模式匹配的唯一信用卡号:

for (String key : map.keySet()) {
    System.out.println("Found a matching credit card: " + key);
}