0

首先,我知道我想像这样向上转换是不寻常的,但请多多包涵。我们通过网站导出获得这些 csv 文件,我们无法以任何其他形式获得它。

现在,进入问题:

我有这个旧代码可以为我完成这个过程。它基本上读取每一行,然后挑选出,s 之间的每个值。这对于我转换的一些样本非常有用,但是当它归结为使用给定的样本时,一些值不合适。

我在 Notepad++ 中打开了这些文件,并意识到某些单元格本身包含,s。"CSV 文件通过用s包围这些单元格来解决此问题。请参阅以下示例:

.

这可以正常工作:

John,Smith,johnsmith@email.com,burgers

但是,这不会:

John,Smith,johnsmith@email.com,"burgers, french fries"

.

不幸的是,我的代码 ( String strar[] = thisLine.split(",");) 没有考虑到某些单元格包含逗号,并将它们分成不同的列,例如:"burgersfrench fries".

.

如何让我的程序有效地将"s 包围的文本视为单个值,而不是两个单独的值?

.

让我知道我是否可以为你们解决任何其他问题。

非常感谢您的帮助,

贾斯蒂安

4

4 回答 4

3

只需按字符检查 CSV 字符,并在出现报价时设置切换。这是一个启动示例:

public static List<List<String>> parseCsv(InputStream input, char separator) 
    throws IOException 
{
    BufferedReader reader = null;
    List<List<String>> csv = new ArrayList<List<String>>();
    try {
        reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
        for (String record; (record = reader.readLine()) != null;) {
            boolean quoted = false;
            StringBuilder fieldBuilder = new StringBuilder();
            List<String> fields = new ArrayList<String>();
            for (int i = 0; i < record.length(); i++) {
                char c = record.charAt(i);
                fieldBuilder.append(c);
                if (c == '"') {
                    quoted = !quoted;
                }
                if ((!quoted && c == separator) || i + 1 == record.length()) {
                    fields.add(fieldBuilder.toString().replaceAll(separator + "$", "")
                        .replaceAll("^\"|\"$", "").replace("\"\"", "\"").trim());
                    fieldBuilder = new StringBuilder();
                }
            }
            csv.add(fields);
        }
    } finally {
        if (reader != null) try { reader.close(); } catch (IOException logOrIgnore) {}
    }
    return csv;
}

但是,您也可以获取任何可能具有更多功能的第三方Java CSV API等等。

于 2010-07-12T00:00:27.577 回答
1

Managed to answer my own question. With a bit of searching, I managed to find this little pdf here:

http://www.objectmentor.com/resources/articles/tfd.pdf

From there, I managed to adopt the code on page 35 to work with my program. All credit goes to Jeff Langr, 2001. All I did was make it work with some of Java's current standards.

Here's the code for all the people who may encounter this problem in the future.

import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;

public class CSVReader {

    private BufferedReader reader;
    private String line;
    private static final String DOUBLE_QUOTE = "\"";
    private static final String COMMENT_SYMBOL = "#";
    private static final char stateINIT = 'S';
    private static final char stateCOMMENT = '#';
    private static final char stateQUOTED_DATA = 'q';
    private static final char stateQUOTE_IN_QUOTED_DATA = 'Q';
    private static final char stateDATA = 'D';
    private static final char stateNEW_TOKEN = 'N';
    private static final char stateWHITESPACE = 'W';

    public CSVReader(String filename) throws IOException {
        reader = new BufferedReader(new java.io.FileReader(filename));
        loadNextNonCommentLine();
    }

    public ArrayList<String> next() throws IOException {
        if (line == null)
            throw new IOException("Read past end of file");
        ArrayList<String> columns = columnsFromCSVRecord(line);
        loadNextNonCommentLine();
        return columns;
    }

    public boolean hasNext() {
        return line != null;
    }

    void loadNextNonCommentLine() throws IOException {
        do
            line = reader.readLine();
        while (line != null && line.startsWith(COMMENT_SYMBOL));
        if (line == null)
            reader.close();
    }

    public ArrayList<String> columnsFromCSVRecord(String line) throws IOException {
        char state = stateINIT;
        char ch;
        int i = 0;
        ArrayList<String> tokens = new ArrayList<String>();
        StringBuffer buffer = new StringBuffer();
        char[] charArray = line.toCharArray();
        while (i < charArray.length) {
            ch = charArray[i++];
            switch (state) {
            case stateINIT:
                switch (ch) {
                case '"':
                    buffer.append(ch);
                    state = stateQUOTED_DATA;
                    break;
                case ',':
                    state = stateNEW_TOKEN;
                    tokens.add(clean(buffer));
                    buffer = new StringBuffer();
                    break;
                case '\t':
                case ' ':
                    break;
                case '#':
                    state = stateCOMMENT;
                    break;
                default:
                    state = stateDATA;
                    buffer.append(ch);
                    break;
                }
                break;
            case stateCOMMENT:
                break;
            case stateQUOTED_DATA:
                switch (ch) {
                case '"':
                    buffer.append(ch);
                    state = stateQUOTE_IN_QUOTED_DATA;
                    break;
                default:
                    buffer.append(ch);
                    break;
                }
                break;
            case stateQUOTE_IN_QUOTED_DATA:
                switch (ch) {
                case '"':
                    state = stateQUOTED_DATA;
                    break;
                case ',':
                    state = stateNEW_TOKEN;
                    tokens.add(clean(buffer));
                    buffer = new StringBuffer();
                    break;
                case ' ':
                case '\t':
                    break;
                case '#':
                    tokens.add(clean(buffer));
                    state = stateCOMMENT;
                    break;
                default:
                    throw new IOException("badly formed CSV record:" + line);
                }
                break;
            case stateDATA:
                switch (ch) {
                case '#':
                    tokens.add(clean(buffer));
                    state = stateCOMMENT;
                    break;
                case ',':
                    state = stateNEW_TOKEN;
                    tokens.add(clean(buffer));
                    buffer = new StringBuffer();
                    break;
                default:
                    buffer.append(ch);
                    break;
                }
                break;
            case stateNEW_TOKEN:
                switch (ch) {
                case '#':
                    tokens.add(clean(buffer));
                    state = stateCOMMENT;
                    break;
                case ',':
                    tokens.add(clean(buffer));
                    buffer = new StringBuffer();
                    break;
                case ' ':
                case '\t':
                    state = stateWHITESPACE;
                    break;
                case '"':
                    buffer.append(ch);
                    state = stateQUOTED_DATA;
                    break;
                default:
                    state = stateDATA;
                    buffer.append(ch);
                    break;
                }
                break;
            case stateWHITESPACE:
                switch (ch) {
                case '#':
                    state = stateCOMMENT;
                    break;
                case ',':
                    state = stateNEW_TOKEN;
                    // ACCEPT NEW EMPTY COLUMN HERE??
                    break;
                case '"':
                    buffer.append(ch);
                    state = stateQUOTED_DATA;
                    break;
                case ' ':
                case '\t':
                    break;
                default:
                    state = stateDATA;
                    buffer.append(ch);
                    break;
                }
                break;
            default:
                break;
            }
        }
        if (state == stateQUOTED_DATA)
            throw new IOException("Unmatched quotes in line:\n" + line);
        if (state != stateCOMMENT)
            tokens.add(clean(buffer));
        return tokens;
    }

    public String clean(StringBuffer buffer) {
        String string = buffer.toString().trim();
        if (string.startsWith(DOUBLE_QUOTE))
            return string.substring(1, string.length() - 1);
        return string;
    }
}
于 2010-07-12T03:06:07.503 回答
1

我知道这并不能真正帮助您解决眼前的问题,但我的建议是:根本不要这样做。如果您只处理嵌入式逗号,您将非常幸运。嵌入式双引号呢?嵌入式换行符?等等……等等……

很诚实?答案是找到一个解析 CSV 的库并使用它。我很确定世界上几乎每个开发人员都陷入了“哦,CSV 是一种如此简单的格式,我会自己解析它”的把戏。我知道有。

一篇很棒的帖子,关于滚动你自己的 CSV 解析器的问题,我喜欢提到人们(我就是那样残忍)。这是一篇与 .NET 相关的帖子,但它仍然适用于您的情况。请注意,您只完成了第 2 步(共 5 步)……还有很多工作要做。

于 2010-07-12T02:03:30.117 回答
0

与其依赖 split(),不如编写自己的解析器来处理这种情况。让您的语法将一对 " " 或 ' ' 之间的所有字符视为单个标记。

于 2010-07-11T23:53:13.397 回答