Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/364.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 创建一个支持字符串的番石榴拆分器_Java_Regex_Split_Guava - Fatal编程技术网

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(...);

我想为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(...);
  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,我完全同意。我发布它主要是为了展示你最终会得到一个多么可怕的正则表达式:这样的野兽不应该在野外被释放!:)我也有同样的问题,但我甚至没有想到一个新的正则表达式阿玛彻,谢谢!