使用以下表达式:
(?<!XYZ\d{8})(?>REF[A-Z]*)?(\d{3}+)(\d{6}+)(\d{3}+)
我得到意想不到的比赛。请解释为什么会发生以下情况:
XYZ12345678123456789123
- 123456781234
上的匹配项 - 我希望它仅匹配123456789123
,因为它是唯一没有(?<!XYZ\d{8})
奇怪的是,如果我使用XYZ12345678REF123456789876
作为输入,则会返回123456789876
但不是REF123456789876
的匹配项。它正确地忽略了XYZ12345678
,但它没有选择可选的REF字符。
基本上我想要实现的是从包含两个标识符的字符串中提取12位数字标识符。第一个标识符的格式为XYZ\d{8}
,第二个标识符的格式为(?>REF[A-Z]*)?(\d{3}+)(\d{6}+)(\d{3}+)
为了避免匹配XYZ12345678123456789123
等字符串中错误的12位数,我想说 - 只要数字不是XYZ\d{8}
类型标识符的一部分,就得到12位数字。
以下是我想要实现的几个例子
XYZ12345678123456789123 match on 123456789123
123456789123 match on 123456789123
XYZ12345678REF123456789123 should match on REF123456789123
12345678912 no match because not 12 digits
REF123456789123 match on REF123456789123
REF12345678912 no match because not 12 digits
XYZ12345678123456789123ABC match on 123456789123
XYZ123456789123 No match
XYZ1234567891234 no match
答案 0 :(得分:2)
你几乎在那里。将(?<!XYZ\\d{8})
更改为(?<!XYZ\\d{0,7})
。您需要检查您的匹配项是否不是之前标识符XYZ\\d{8}
的一部分,这意味着它不能
XYZ
XYZ1
XYZ12
XYZ1234567
之前。
基于您的示例进行演示
String[] data ={
"XYZ12345678123456789123", //123456789123
"123456789123", //123456789123
"XYZ12345678REF123456789123 ", //REF123456789123
"12345678912", //no match because not 12 digits
"REF123456789123", //REF123456789123
"REF12345678912", //no match because not 12 digits
"XYZ12345678123456789123ABC", //123456789123
"XYZ123456789123", //no match
"XYZ1234567891234", //no match
};
Pattern p = Pattern.compile("(?<!XYZ\\d{0,7})(?>REF[A-Z]*)?(\\d{3}+)(\\d{6}+)(\\d{3}+)");
for (String s:data){
System.out.printf("%-30s",s);
Matcher m = p.matcher(s);
while (m.find())
System.out.print("match: "+m.group());
System.out.println();
}
输出:
XYZ12345678123456789123 match: 123456789123
123456789123 match: 123456789123
XYZ12345678REF123456789123 match: REF123456789123
12345678912
REF123456789123 match: REF123456789123
REF12345678912
XYZ12345678123456789123ABC match: 123456789123
XYZ123456789123
XYZ1234567891234
答案 1 :(得分:1)
引擎开始查看字符串中的第一个字符
如果字符串是“ABCDEF”且正则表达式是(?<!C)...
查看A
,它看到左侧没有C
。
断言得到满足,然后匹配ABC
。
断言只是在它所处的当前位置测试它周围的字符。
它们不会强制引擎首先找到C
并匹配后面的字符。
修改
从你的例子中你需要这样的东西,这是固定的 如果没有锚定,可能会更难。
此外,Java没有分支重置,因此您必须查看哪个组 群集匹配。
# "^(?:(?:XYZ\\d{8})(\\d{3})(\\d{6})(\\d{3})|(?:REF)(\\d{3})(\\d{6})(\\d{3})|(\\d{3})(\\d{6})(\\d{3}))"
^
(?:
(?: XYZ \d{8} )
( \d{3} ) # (1)
( \d{6} ) # (2)
( \d{3} ) # (3)
|
(?: REF )
( \d{3} ) # (4)
( \d{6} ) # (5)
( \d{3} ) # (6)
|
( \d{3} ) # (7)
( \d{6} ) # (8)
( \d{3} ) # (9)
)
替代方案,
# "^(?:(?:XYZ\\d{8})|(?:REF))?(\\d{3})(\\d{6})(\\d{3})"
^
(?:
(?: XYZ \d{8} )
| (?: REF )
)?
( \d{3} ) # (1)
( \d{6} ) # (2)
( \d{3} ) # (3)
答案 2 :(得分:0)
你可以检查它的匹配是不是以前的标识符XYZ \ d {8}的一部分,这意味着它不能
XYZ
XYZ1
XYZ12
...
XYZ1234567
之前。
此外,Java没有分支重置,因此您必须查看哪个组 群集匹配。
我会做出改变
(?<!XYZ\\d{8}) to (?<!XYZ\\d{0,7}).
希望这会有所帮助。