我有许多EDIFACT格式的行需要在+
上进行标记化。但是,根据EDIFACT规范,可以使用?
转义字符。例如:??
为?
,?+
为+
,?:
为:
。 ?+
是字段的一部分,因此不应被视为分隔符。
我使用负面的lookbehind来处理+
之后的?
:
delimiter = "\\+";
String[] tokens = data.split("(?<!\\?)" + delimiter);
这会分开
a+b+c
加入a
,b
和c
a?+b+c
加入a?+b
和c
但是,当涉及??
转义序列时,它会失败:
a??+b+c
会产生2个代币:a??+b
,c
而它确实应该是3个令牌:a?
,b
和c
另一方面:a???+b+c
应该产生两个令牌:a???+b
和c
有没有办法用负面的后视来实现这个目标?
如果你愿意的话,这是一个可以玩的可运行的测试。
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
assertTokens("a+b+c", "a", "b", "c");
assertTokens("a?+b+c", "a?+b", "c");
assertTokens("a??+b+c", "a??", "b", "c");
assertTokens("a???+b+c", "a???+b", "c");
}
private static void assertTokens(String data, String... expectedTokens) {
String delimiter = "\\+";
String[] tokens = data.split("(?<!\\?)" + delimiter);
if(!Arrays.deepEquals(tokens, expectedTokens)) {
throw new IllegalStateException("Not equals for " + data);
}
}
}
答案 0 :(得分:4)
使用匹配更容易进行标记化,而不是拆分。在你的情况下,对于拆分工作,你必须使用java不支持的可变长度lookbehind。
尝试以下正则表达式:
(?:[^+:?]++|\?.)+
(我使用占有量词(++
)纯粹作为优化来避免无用的回溯)
如果您想匹配空标记(a++b
让步,a
,空字符串和b
),则正则表达式会变得更复杂:
(?:[^+:?\r\n]++|\?.)+|(?<=[+:]|^)(?=[+:]|$)
这意味着
\r\n
添加到论坛中,因此换行符不匹配)我添加了m
选项,这意味着^
和$
匹配每行的开头和结尾。
答案 1 :(得分:0)
供参考:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) {
assertTokens("+", "a+b+c", "a", "b", "c");
assertTokens("+", "a?+b+c", "a?+b", "c");
assertTokens("+", "a??+b+c", "a??", "b", "c");
assertTokens("+", "a???+b+c", "a???+b", "c");
assertTokens("+", "a?'??+b+c", "a?'??", "b", "c");
assertTokens("\\:", "a???:b:c", "a???:b", "c");
assertTokens("\\:", "a????:b:c", "a????", "b", "c");
}
private static void assertTokens(String delim, String data, String... expectedTokens) {
Pattern pattern = Pattern.compile("(?:[^" + delim + ":?]++|\\?.)+");
Matcher matcher = pattern.matcher(data);
List<String> tokens = new ArrayList<>();
while (matcher.find()) {
tokens.add(matcher.group());
}
if(!Arrays.deepEquals(tokens.toArray(), expectedTokens)) {
for (String token: tokens) {
System.out.println(token);
}
throw new IllegalStateException("Not equals for " + data);
}
}
}