Java 创建一个支持字符串的番石榴拆分器
我想为Java创建一个番石榴拆分器,它可以将Java字符串作为一个块来处理。例如,我希望以下断言为真:Java 创建一个支持字符串的番石榴拆分器,java,regex,split,guava,Java,Regex,Split,Guava,我想为Java创建一个番石榴拆分器,它可以将Java字符串作为一个块来处理。例如,我希望以下断言为真: @Test public void testSplitter() { String toSplit = "a,b,\"c,d\\\"\",e"; List<String> expected = ImmutableList.of("a", "b", "c,d\"","e"); Splitter splitter = Splitter.onPattern(...);
@Test
public void testSplitter() {
String toSplit = "a,b,\"c,d\\\"\",e";
List<String> expected = ImmutableList.of("a", "b", "c,d\"","e");
Splitter splitter = Splitter.onPattern(...);
List<String> actual = ImmutableList.copyOf(splitter.split(toSplit));
assertEquals(expected, actual);
}
@测试
公共void testSplitter(){
字符串toSplit=“a,b,\”c,d\\\”,e”;
预期列表=不可变列表,共有(“a”、“b”、“c、d\”和“e”);
Splitter Splitter=Splitter.onPattern(…);
List-actual=ImmutableList.copyOf(spliter.split(toSplit));
资产质量(预期、实际);
}
< >我可以编写正则表达式来查找所有元素,不考虑“,”,但我找不到作为分隔符使用的正则表达式。
如果不可能,请直接说出来,然后我将从findAll正则表达式构建列表。这似乎是您应该使用CSV库(例如for)的内容。分隔值和处理引用块之类的情况就是它们的全部内容。您可以按照以下模式进行拆分:
\s*,\s*(?=((\\["\\]|[^"\\])*"(\\["\\]|[^"\\])*")*(\\["\\]|[^"\\])*$)
使用(?x)
标志时,哪个选项看起来(有点)更友好:
(?x) # enable comments, ignore space-literals
\s*,\s* # match a comma optionally surrounded by space-chars
(?= # start positive look ahead
( # start group 1
( # start group 2
\\["\\] # match an escaped quote or backslash
| # OR
[^"\\] # match any char other than a quote or backslash
)* # end group 2, and repeat it zero or more times
" # match a quote
( # start group 3
\\["\\] # match an escaped quote or backslash
| # OR
[^"\\] # match any char other than a quote or backslash
)* # end group 3, and repeat it zero or more times
" # match a quote
)* # end group 1, and repeat it zero or more times
( # open group 4
\\["\\] # match an escaped quote or backslash
| # OR
[^"\\] # match any char other than a quote or backslash
)* # end group 4, and repeat it zero or more times
$ # match the end-of-input
) # end positive look ahead
但即使在这个评论版本中,它仍然是一个怪物。用简单的英语,这个正则表达式可以解释如下:
a
b
"c,d\""
e
匹配一个可选地由空格字符包围的逗号,仅当向前看该逗号时(一直到字符串末尾!),引号数为零或偶数,而忽略转义引号或转义反斜杠
因此,在看到这一点之后,您可能会同意Colin(我同意!)的观点,即在这种情况下,使用某种CSV解析器是可行的
请注意,上面的正则表达式将保留标记周围的QOUTE,即字符串a,b,“c,d\”,e
(作为文本:“a,b,\'c,d\\\”,e“
)将按如下方式拆分:
a
b
"c,d\""
e
这是一个Guava特性请求:我有同样的问题(除了不需要支持引号字符转义)。对于这样简单的事情,我不想再增加一个库。然后我想到,我需要一个可变的字符匹配器。正如巴特·基尔斯的解决方案一样,它保持了引用的特点
public static Splitter quotableComma() {
return on(new CharMatcher() {
private boolean inQuotes = false;
@Override
public boolean matches(char c) {
if ('"' == c) {
inQuotes = !inQuotes;
}
if (inQuotes) {
return false;
}
return (',' == c);
}
});
}
@Test
public void testQuotableComma() throws Exception {
String toSplit = "a,b,\"c,d\",e";
List<String> expected = ImmutableList.of("a", "b", "\"c,d\"", "e");
Splitter splitter = Splitters.quotableComma();
List<String> actual = ImmutableList.copyOf(splitter.split(toSplit));
assertEquals(expected, actual);
}
公共静态拆分器quotableComma(){
返回(新的CharMatcher(){
私有布尔inQuotes=false;
@凌驾
公共布尔匹配(字符c){
如果(“”==c){
inQuotes=!inQuotes;
}
如果(以引号引){
返回false;
}
返回(','==c);
}
});
}
@试验
public void testQuotableComma()引发异常{
字符串toSplit=“a,b,\'c,d\',e”;
预期列表=不可变列表,共有(“a”、“b”、“c、d”、“e”);
Splitter Splitter=Splitters.quotableComma();
List-actual=ImmutableList.copyOf(spliter.split(toSplit));
资产质量(预期、实际);
}
对@Rage Steel的答案稍加改进
final static CharMatcher notQuoted = new CharMatcher() {
private boolean inQuotes = false;
@Override
public boolean matches(char c) {
if ('"' == c) {
inQuotes = !inQuotes;
}
return !inQuotes;
};
final static Splitter SPLITTER = Splitter.on(notQuoted.and(CharMatcher.anyOf(" ,;|"))).trimResults().omitEmptyStrings();
然后呢,
public static void main(String[] args) {
final String toSplit = "a=b c=d,kuku=\"e=f|g=h something=other\"";
List<String> sputnik = SPLITTER.splitToList(toSplit);
for (String s : sputnik)
System.out.println(s);
}
publicstaticvoidmain(字符串[]args){
最后一个字符串toSplit=“a=bc=d,kuku=\”e=f | g=h something=other\”;
List sputnik=spliter.splitToList(toSplit);
用于(字符串s:sputnik)
系统输出打印项次;
}
注意线程安全性(或者,为了简化,没有任何问题)我已经+1了你的答案,因为它(几乎)是这样的使用我想要的工具,这正是我想要的,但为了可读性,我接受了科林的答案。无论如何,非常非常好的东西!@ogregoire,我完全同意。我发布它主要是为了展示你最终会得到一个多么可怕的正则表达式:这样的野兽不应该在野外被释放!:)我也有同样的问题,但我甚至没有想到一个新的正则表达式阿玛彻,谢谢!