我们正在为电子邮件执行一些数据丢失防护,但问题是当人们多次回复电子邮件时,有时信用卡号或帐号会多次出现。
我们怎样才能让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
答案 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)
<强>详情:
/\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);
}