Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/378.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_Algorithm - Fatal编程技术网

Java中通过逗号或双引号对拆分字符串的优雅算法

Java中通过逗号或双引号对拆分字符串的优雅算法,java,algorithm,Java,Algorithm,问题很简单 CSV文件如下所示: 1, "John", "John Joy" 1, "John", "Joy, John" 如果我想得到每一列,我只需要使用String[]splits=line.split 如果CSV文件如下所示: 1, "John", "John Joy" 1, "John", "Joy, John" 所以在双引号对中有一个逗号。上面的拆分将不再有效,因为我想要Joy,John作为一个完整的部分 那么,是否有一种优雅/简单的算法来处理这种情况 编辑: 请不要认为这是一

问题很简单

CSV文件如下所示:

1, "John", "John Joy"
1, "John", "Joy, John"
如果我想得到每一列,我只需要使用String[]splits=line.split

如果CSV文件如下所示:

1, "John", "John Joy"
1, "John", "Joy, John"
所以在双引号对中有一个逗号。上面的拆分将不再有效,因为我想要Joy,John作为一个完整的部分

那么,是否有一种优雅/简单的算法来处理这种情况

编辑:

请不要认为这是一个正式的CSV解析的事情。我只是将CSV用作需要拆分的用例


我真正想要的不是一个合适的CSV解析器,相反,我只想要一个算法,它可以在考虑双引号的情况下用逗号正确地分割一行。

如果不这样做是为了学习,最好使用现有库,而不是编写自定义实现。 因为CSV有一些您在自定义实现中可能会错过的细节,而且通常库是经过良好测试的

在这里你可以找到一些好的

编辑

我创建了一个方法来解析您的字符串,但由于我没有对它进行很好的测试,它的工作可能并不完美。 这可能只是你的一个起点,你可以进一步改进它

    String inputString = "1, \"John\",\"Joy, John\"";
    char quote = '"';
    List<String> csvList = new ArrayList<String>();
    boolean inQuote = false;
    int lastStart = 0;
    for (int i = 0; i < inputString.length(); i++) {
        if ((i + 1) == inputString.length()) {
            //if this is the last character
            csvList.add(inputString.substring(lastStart, i + 1));
        }
        if (inputString.charAt(i) == quote) {
            //if the character is quote
            if (inQuote) {
                inQuote = false;
                continue; //escape
            }
            inQuote = true;
            continue;
        }
        if (inputString.charAt(i) == ',') {
            if (inQuote) continue;
            csvList.add(inputString.substring(lastStart, i));
            lastStart = i + 1;
        }
    }
    System.out.println(csvList);
有问题吗

如果你能得到像这样的线,约翰,乔伊,约翰
Joy,John?

如果不是为了学习,最好使用现有库,而不是编写自定义实现。 因为CSV有一些您在自定义实现中可能会错过的细节,而且通常库是经过良好测试的

在这里你可以找到一些好的

编辑

我创建了一个方法来解析您的字符串,但由于我没有对它进行很好的测试,它的工作可能并不完美。 这可能只是你的一个起点,你可以进一步改进它

    String inputString = "1, \"John\",\"Joy, John\"";
    char quote = '"';
    List<String> csvList = new ArrayList<String>();
    boolean inQuote = false;
    int lastStart = 0;
    for (int i = 0; i < inputString.length(); i++) {
        if ((i + 1) == inputString.length()) {
            //if this is the last character
            csvList.add(inputString.substring(lastStart, i + 1));
        }
        if (inputString.charAt(i) == quote) {
            //if the character is quote
            if (inQuote) {
                inQuote = false;
                continue; //escape
            }
            inQuote = true;
            continue;
        }
        if (inputString.charAt(i) == ',') {
            if (inQuote) continue;
            csvList.add(inputString.substring(lastStart, i));
            lastStart = i + 1;
        }
    }
    System.out.println(csvList);
有问题吗

如果你能得到像这样的线,约翰,乔伊,约翰
Joy,John?

中的两个引号使用正则表达式非常优雅。 抱歉,我不熟悉Java正则表达式,所以我的示例是Lua: 这个例子没有考虑到在引用的文本中可能有换行符,而在引用的文本中原始的引号字符会加倍

--- file.csv
1, "John", "John Joy"
2, "John", "Joy, John"

--- Lua code
for line in io.lines 'file.csv' do
   print '==='
   for _, s in (line..','):gmatch '%s*("?)(.-)%1%s*,' do
      print(s)
   end
end

--- Output
===
1
John
John Joy
===
2
John
Joy, John

使用正则表达式非常优雅。 抱歉,我不熟悉Java正则表达式,所以我的示例是Lua: 这个例子没有考虑到在引用的文本中可能有换行符,而在引用的文本中原始的引号字符会加倍

--- file.csv
1, "John", "John Joy"
2, "John", "Joy, John"

--- Lua code
for line in io.lines 'file.csv' do
   print '==='
   for _, s in (line..','):gmatch '%s*("?)(.-)%1%s*,' do
      print(s)
   end
end

--- Output
===
1
John
John Joy
===
2
John
Joy, John

可以从正则表达式开始:

[^",]*|"[^"]*"
它匹配不包含逗号的非引号字符串或引号字符串。然而,还有很多问题,包括:

你的输入中逗号后面真的有空格吗?或者,更一般地说,您是否允许不完全位于字段第一个字符处的引号

如何在包含引号的字段周围加引号

根据你如何回答这个问题,你可能会得到不同的正则表达式。事实上,使用CSV解析库的常规建议与处理角落案例无关;这是关于不必考虑它们,因为您假定标准的CSV处理,不管解析库的作者认为这可能是什么。真是一团糟

我成功地使用了一个正则表达式,尽管它与CSV不兼容:

(?:[^",]|"[^"]*")*
这与第一个非常相似,只是它允许任何数量的串联字段,因此以下两个字段都可以识别为单个字段:

"John"", Mary"
John", "Mary
CSV标准将第一个视为代表:

John", Mary    -- internal quote
并将第二个字段中的引号视为普通字符,从而生成两个字段。所以YMMV

在任何情况下,一旦您决定一个合适的正则表达式,算法都很简单。在伪代码中,因为我远不是Java专家

repeat:
   match the regex at the current position
     and append the result to the result;
   if the match fails:
     report error
   if the match goes to the end of the string:
     done
   if the next character is a ',':
     advance the position by one
   otherwise:
     report error

根据正则表达式的不同,报告错误的两种情况可能是不可能的。通常,如果引用的字段未终止,并且您需要决定是否允许在引用的字段中添加新行,则会触发第一个。如果使用了我提供的第一个正则表达式,但没有立即在带引号的字符串后面加逗号,则可能会出现第二种情况。

可以从正则表达式开始:

[^",]*|"[^"]*"
// use regxep with matcher

String string1 = "\"John\", \"John Joy\"";
String string2 = "\"John\", \"Joy, John\"";
Pattern pattern = Pattern.compile("\"[^\"]+\"");

Matcher matcher = pattern.matcher(string1);
System.out.println("string1: " + string1);
int start = 0;
while(matcher.find(start)){
    System.out.println(matcher.group());
    start = matcher.end() + 1;
    if(start > string1.length())
    break;
}

matcher = pattern.matcher(string2);
System.out.println("string2: " + string2);
start = 0;
while(matcher.find(start)){
    System.out.println(matcher.group());
    start = matcher.end() + 1;
    if(start > string2.length())
    break;
}
它匹配不包含逗号的非引号字符串或引号字符串。然而,还有很多问题,包括:

你的输入中逗号后面真的有空格吗?或者,更一般地说,您是否允许不完全位于字段第一个字符处的引号

如何在包含引号的字段周围加引号

根据你如何回答这个问题,你可能会得到不同的正则表达式。事实上,使用CSV解析库的常规建议与处理角落案例无关;这是关于不必考虑他们,因为你 我使用标准的CSV处理,不管根据解析库的作者是什么。真是一团糟

我成功地使用了一个正则表达式,尽管它与CSV不兼容:

(?:[^",]|"[^"]*")*
这与第一个非常相似,只是它允许任何数量的串联字段,因此以下两个字段都可以识别为单个字段:

"John"", Mary"
John", "Mary
CSV标准将第一个视为代表:

John", Mary    -- internal quote
并将第二个字段中的引号视为普通字符,从而生成两个字段。所以YMMV

在任何情况下,一旦您决定一个合适的正则表达式,算法都很简单。在伪代码中,因为我远不是Java专家

repeat:
   match the regex at the current position
     and append the result to the result;
   if the match fails:
     report error
   if the match goes to the end of the string:
     done
   if the next character is a ',':
     advance the position by one
   otherwise:
     report error

根据正则表达式的不同,报告错误的两种情况可能是不可能的。通常,如果引用的字段未终止,并且您需要决定是否允许在引用的字段中添加新行,则会触发第一个。如果使用了我提供的第一个正则表达式,但没有立即在带引号的字符串后面加逗号,则可能会出现第二种情况。

首先在引号中拆分字符串。奇数段将引用内容;即使是一个,也必须用逗号再拆分一次。我在日志上使用它,引用的文本没有转义引号,就像这个问题一样

// use regxep with matcher

String string1 = "\"John\", \"John Joy\"";
String string2 = "\"John\", \"Joy, John\"";
Pattern pattern = Pattern.compile("\"[^\"]+\"");

Matcher matcher = pattern.matcher(string1);
System.out.println("string1: " + string1);
int start = 0;
while(matcher.find(start)){
    System.out.println(matcher.group());
    start = matcher.end() + 1;
    if(start > string1.length())
    break;
}

matcher = pattern.matcher(string2);
System.out.println("string2: " + string2);
start = 0;
while(matcher.find(start)){
    System.out.println(matcher.group());
    start = matcher.end() + 1;
    if(start > string2.length())
    break;
}
    boolean quoted = false;
    for(String q : str.split("\"")) {
        if(quoted)
            System.out.println(q.trim());
        else
            for(String s : q.split(","))
                if(!s.trim().isEmpty())
                    System.out.println(s.trim());
        quoted = !quoted;
    }

首先在引号上拆分字符串。奇数段将引用内容;即使是一个,也必须用逗号再拆分一次。我在日志上使用它,引用的文本没有转义引号,就像这个问题一样

    boolean quoted = false;
    for(String q : str.split("\"")) {
        if(quoted)
            System.out.println(q.trim());
        else
            for(String s : q.split(","))
                if(!s.trim().isEmpty())
                    System.out.println(s.trim());
        quoted = !quoted;
    }


CSV文件如下所示:一个简单的文件就是这样。复杂的字段可以在引用的字段中有换行符。因此,如果您正在逐行阅读它,请注意,除非您的行感知代码正在处理引号内的换行符,否则您的行变量只能包含记录的一部分。您需要一个CSV解析器,一个简单的状态机就可以了。如果您所说的优雅是指类似于单个正则表达式的东西:没有。CSV比看上去复杂得多:多行字段、转义引号等等。不过,您可以使用CSV解析器库:例如OpenCSV,但肯定也有一个Apache解析器库。如何处理上述两种情况?CSV文件如下所示:一个简单的文件就可以。复杂的字段可以在引用的字段中有换行符。因此,如果您正在逐行阅读它,请注意,除非您的行感知代码正在处理引号内的换行符,否则您的行变量只能包含记录的一部分。您需要一个CSV解析器,一个简单的状态机就可以了。如果您所说的优雅是指类似于单个正则表达式的东西:没有。CSV比看上去复杂得多:多行字段、转义引号等等。不过,您可以使用CSV解析器库:例如OpenCSV,但肯定也有一个Apache解析器库。只处理上述两种情况如何?只处理上述两种情况如何?@Jackson Tale-Joy中的两个引号,John不适合CSV。但最初的引号会加倍。例如,John说:OK将成为John说:CSV中的OK。就像这样:1,John,Joy,John如何处理上述两个案例?@Jackson Tale-Joy中的两个引号,John不适合CSV。但最初的引号会加倍。例如,John说:OK将成为John说:CSV中的OK。就像这样:1,John,Joy,如果你能解释你的答案,比如为什么你认为它很优雅或者它所采用的方法等等,那就太好了。亚历克斯:如果你能解释你的答案,比如为什么你认为它很优雅或者它所采用的方法等等,那就太好了。解释一下你的答案。只是不喜欢正则表达式。上面的代码应该按要求拆分str。我认为@Kumar的意思是,仅代码的答案通常是不可接受的,例如,解释一下你的答案。只是不喜欢正则表达式。上面的代码应该按要求拆分str。我认为@Kumar的意思是,仅代码的答案通常是不可接受的,例如。