3

我正在尝试仅使用标准 Java 库来解析用引号括起来的逗号分隔值(我知道这必须是可能的)

作为一个例子 file.txt 包含一个新行的每一行

"Foo","Bar","04042013","04102013","Stuff"
"Foo2","Bar2","04042013","04102013","Stuff2"

但是,当我使用到目前为止编写的代码解析文件时:

import java.io.*;
import java.util.Arrays;
 public class ReadCSV{

    public static void main(String[] arg) throws Exception {

        BufferedReader myFile = new BufferedReader(new FileReader("file.txt"));

        String myRow = myFile.readLine(); 
        while (myRow != null){
            //split by comma separated quote enclosed values
            //BUG - first and last values get an extra quote
            String[] myArray = myRow.split("\",\""); //the problem

            for (String item:myArray) { System.out.print(item + "\t"); }
            System.out.println();
            myRow = myFile.readLine();
        }
        myFile.close();
    }
}

但是输出是

"Foo    Bar     04042013        04102013        Stuff"

"Foo2   Bar2    04042013        04102013        Stuff2"

代替

Foo    Bar     04042013        04102013        Stuff

Foo2   Bar2    04042013        04102013        Stuff2

我知道我在拆分时出错了,但我不知道如何解决它。

4

6 回答 6

4

在进行拆分之前,只需使用下面的行删除 myRow 变量中的第一个双引号和最后一个双引号。

myRow = myRow.substring(1, myRow.length() - 1);

(更新)还要检查 myRow 是否不为空。否则上面的代码会导致异常。例如下面的代码检查 myRow 是否不为空,然后只从字符串中删除双引号。

if (!myRow.isEmpty()) {
    myRow = myRow.substring(1, myRow.length() - 1);
}
于 2013-04-22T07:24:54.107 回答
4

我认为您可能必须采用有状态的方法,基本上就像下面的代码(如果您想允许在值中转义引号,则需要另一种状态):

import java.util.ArrayList;
import java.util.List;


public class CSV {

    public static void main(String[] args) {
        String s = "\"hello, i am\",\"a string\"";
        String x = s;
        List<String> l = new ArrayList<String>();
        int state = 0;
        while(x.length()>0) {
            if(state == 0) {
                if(x.indexOf("\"")>-1) {
                    x = x.substring(x.indexOf("\"")+1).trim();
                    state = 1;
                } else {
                    break;
                }
            } else if(state == 1) {
                if(x.indexOf("\"")>-1) {
                    String found = x.substring(0,x.indexOf("\"")); 
                    System.err.println("found: "+found);
                    l.add(found);
                    x = x.substring(x.indexOf("\"")+1).trim();
                    state = 0;
                } else {
                    throw new RuntimeException("bad format");
                }
            } else if(state == 2) {
                if(x.indexOf(",")>-1) {
                    x = x.substring(x.indexOf(",")+1).trim();
                    state = 0;
                } else {
                    break;
                }
            }
        }
        for(String f : l) {
            System.err.println(f);
        }
    }


}
于 2013-04-22T07:49:28.630 回答
2

相反,您可以使用replaceAll,对我来说,它看起来更适合此任务:

myRow = myRow.replaceAll("\"", "").replaceAll(","," ");

这将用空"替换所有(将删除它们),然后,用空格替换所有(当然你可以增加空格的数量)。

于 2013-04-22T07:25:59.270 回答
1

上面代码片段中的问题是您正在拆分基于 ",". 在您的 Line start"foo","和 end","stuff"上,开始和结束引号不匹配,","因此没有拆分。

所以这绝对不是java中的错误。在您的情况下,您需要自己处理该部分。

您有多种选择。其中一些可能如下所示。1. 如果您确定总会有一个开始"和结束",您可以在拆分之前将它们从 String 中删除。2.如果starting "and"是可选的,可以先勾选with startsWith endsWith,如果存在就去掉,再拆分。

于 2013-04-22T07:31:13.083 回答
0

您可以简单地获取由逗号分隔的字符串,然后删除第一个和最后一个 '"'。=) 希望这有帮助没有太多时间:D

String s = "\"Foo\",\"Bar\",\"04042013\",\"04102013\",\"Stuff\"";
        String[] bufferArray = new String[10];
        String bufferString;
        int i = 0;
        System.out.println(s);

        Scanner scanner = new Scanner(s);
        scanner.useDelimiter(",");

        while(scanner.hasNext()) {
            bufferString = scanner.next();
            bufferArray[i] = bufferString.subSequence(1, bufferString.length() - 1).toString();
            i++;
        }

        System.out.println(bufferArray[0]);
        System.out.println(bufferArray[1]);
        System.out.println(bufferArray[2]);
于 2013-04-22T07:32:47.190 回答
0

此解决方案不如String.split()oneliner 优雅。优点是我们避免了脆弱的字符串操作,即。的使用String.substring()。字符串必须以,"然而结尾。

此版本处理分隔符之间的空格。引号中的分隔符按预期被忽略,转义引号(例如\")也是如此。

String s = "\"F\\\",\\\"oo\"  ,    \"B,ar\",\"04042013\",\"04102013\",\"St,u\\\"ff\"";
Pattern p = Pattern.compile("(.*?)\"\\s*,\\s*\"");
Matcher m = p.matcher(s + ",\""); // String must end with ,"
while (m.find()) {
    String result = m.group(1);
    System.out.println(result);
}
于 2015-02-19T14:02:53.757 回答