解析用引号括起来的逗号分隔值

时间:2013-04-22 07:18:30

标签: java csv

我正在尝试使用标准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

我知道我在Split上出错了,但我不确定如何解决它。

6 个答案:

答案 0 :(得分:4)

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

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

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

if (!myRow.isEmpty()) {
    myRow = myRow.substring(1, myRow.length() - 1);
}

答案 1 :(得分: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);
        }
    }


}

答案 2 :(得分:2)

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

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

这将替换所有"没有任何内容(将删除它们),然后它将用空格替换所有,(当然,您可以增加空格数)。

答案 3 :(得分:1)

上面代码段中的问题是您要根据","拆分字符串。 在您的热线上"foo","开始{结尾","stuff",起始和结束引号与","不匹配,因此没有分割。

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

您有多种选择。其中一些可能如下。 1.如果您确定始终有一个起始"和结束",您可以在分割之前将其从字符串中删除。 2.如果起始""是可选的,您可以先使用startsWith endsWith进行检查,然后在拆分前删除。

答案 4 :(得分: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]);

答案 5 :(得分: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);
}