我有一根绳子,大概是这样的:

foo,bar,c;qual="baz,blurb",d;junk="quux,syzygy"

我想用逗号分开,但我需要忽略引号中的逗号.我该怎么做?似乎regexp方法失败了;我想当我看到一个报价时,我可以手动扫描并进入一个不同的模式,但最好使用现有的库.(edit:我想我指的是已经是JDK的一部分或者已经是Apache Commons等常用库的一部分的库.)

上述字符串应分为:

foo
bar
c;qual="baz,blurb"
d;junk="quux,syzygy"

note:这不是一个CSV文件,它是一个包含在整体 struct 更大的文件中的单个字符串

推荐答案

try :

public class Main { 
    public static void main(String[] args) {
        String line = "foo,bar,c;qual=\"baz,blurb\",d;junk=\"quux,syzygy\"";
        String[] tokens = line.split(",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)", -1);
        for(String t : tokens) {
            System.out.println("> "+t);
        }
    }
}

输出:

> foo
> bar
> c;qual="baz,blurb"
> d;junk="quux,syzygy"

换句话说:split on the comma only if that comma has zero, or an even number of quotes ahead of it.

或者,对眼睛更友好一点:

public class Main { 
    public static void main(String[] args) {
        String line = "foo,bar,c;qual=\"baz,blurb\",d;junk=\"quux,syzygy\"";

        String otherThanQuote = " [^\"] ";
        String quotedString = String.format(" \" %s* \" ", otherThanQuote);
        String regex = String.format("(?x) "+ // enable comments, ignore white spaces
                ",                         "+ // match a comma
                "(?=                       "+ // start positive look ahead
                "  (?:                     "+ //   start non-capturing group 1
                "    %s*                   "+ //     match 'otherThanQuote' zero or more times
                "    %s                    "+ //     match 'quotedString'
                "  )*                      "+ //   end group 1 and repeat it zero or more times
                "  %s*                     "+ //   match 'otherThanQuote'
                "  $                       "+ // match the end of the string
                ")                         ", // stop positive look ahead
                otherThanQuote, quotedString, otherThanQuote);

        String[] tokens = line.split(regex, -1);
        for(String t : tokens) {
            System.out.println("> "+t);
        }
    }
}

产生的结果与第一个示例相同.

编辑

正如@MikeFHay在 comments 中提到的:

我更喜欢使用Guava's Splitter,因为它有更合理的默认值(参见上面关于将空匹配项修剪为String#split()的讨论,所以我做了:

Splitter.on(Pattern.compile(",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)"))

Java相关问答推荐

在FML中删除关键帧动画

Mat. n_Delete()和Mat. n_release的区别

JsonPath在多个线程中返回错误的值

如何使用AWS CLI从S3存储桶中的所有对象中删除用户定义的元数据?

如何打印本系列的第n项y=-(1)-(1+2)+(1+2+3)+(1+2+3+4)-(1+2+3+4+5)...Java中的(1+2+3+4...+n)

查找剩余的枚举

Spring和可编辑";where";@Query

我可以在MacOS上使用什么Java函数来在适当的设备上以适当的音量播放适当的alert 声音?

无法使用Freemarker从XML中读取重复的标记值

我如何为我的Java抵押贷款代码执行加薪操作(&Q)

如何在盒子的顶部和底部创建两张不同图片(大小相同)的盒子?

Java中HashSet的搜索时间与TreeSet的搜索时间

在一行中检索字符分隔字符串的第n个值

嘲笑黄瓜中的对象

为什么我不能建立输入/输出流?Java ServerSocket

IntelliJ IDEA中的JavaFX应用程序无法在资源中找到CSS文件

Java CDI:@Singleton@Startup@Inject无法实现接口

如何通过用户ID向用户发送私信

如何使用jOOQ在PostgreSQL中从枚举类型生成Java枚举

整数->;双取消框,但双->;int不';t开箱.为什么?