Проблемы преобразования CSV в XLS в Java? Необходим только основной опыт Java - вопрос, не связанный с импортом - PullRequest
0 голосов
/ 12 июля 2010

Прежде всего, я понимаю, что это необычно, что я хочу конвертировать, как это, но, пожалуйста, потерпите меня.Мы получаем эти CSV-файлы через экспорт веб-сайта, и у нас нет возможности получить его в любой другой форме.

Теперь, на вопрос:

У меня есть этот старый код, который будет выполнять этот процесс длямне.Он в основном читает каждую строку, а затем выбирает каждое значение между , с.Это отлично работает для некоторых сэмплов, которые я конвертировал, но когда дело дошло до работы с данными сэмплами, некоторые значения были неуместны.

Я открыл файлы в Notepad ++ и понял, что некоторые ячейки сами по себе, содержащий , с.Файлы CSV работают вокруг этого, окружая эти ячейки " с.См. Примеры ниже:

.

Это будет работать нормально:

John,Smith,johnsmith@email.com,burgers

Это, однако, не будет:

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

.

К сожалению, мой код (String strar[] = thisLine.split(",");) не учитывает, что некоторые ячейки содержат запятые, и разделит их на разные столбцы, такие как: "burgers иfrench fries".

.

Как мне заставить мою программу эффективно обрабатывать текст, окруженный " s, как одно значение, а не как два отдельных?

.

Дайте мне знать, если я смогу кое-что прояснить для вас, ребята.

Большое спасибо за помощь,

Justian

Ответы [ 4 ]

3 голосов
/ 12 июля 2010

Просто проверяйте символ 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 , которая может иметь некоторые дополнительные функции и т. Д.

1 голос
/ 12 июля 2010

удалось ответить на мой собственный вопрос.После небольшого поиска мне удалось найти этот небольшой PDF-файл здесь:

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

Оттуда мне удалось принять код на странице 35 для работы с моей программой.Все кредиты идут на Jeff Langr, 2001.Все, что я сделал, это заставил его работать с некоторыми текущими стандартами Java.

Вот код для всех людей, которые могут столкнуться с этой проблемой в будущем.

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;
    }
}
1 голос
/ 12 июля 2010

Я знаю, что это не на самом деле поможет вам решить вашу непосредственную проблему, но мой совет: не делайте этого вообще. Вам очень повезет, если вам не удастся справиться только со встроенными запятыми. Как насчет встроенных двойных кавычек? Встроенные разрывы строк? и т.д. и т.п. ...

Совершенно верно? Ответ заключается в том, чтобы найти библиотеку, которая анализирует CSV и использует ее. Я почти уверен, что почти каждый разработчик в мире впал в уловку «о, CSV - такой простой формат, я сам его разберу». Я знаю у меня есть.

Там же большая почта о проблемах с рулонным своим собственным CSV Парсерами , который я люблю в виде людей (я жесток, как это). Это пост, связанный с .NET, но он по-прежнему применим к вашей ситуации. Обратите внимание, что вы только на шаге 2 из 5 ... впереди еще много.

0 голосов
/ 12 июля 2010

Вместо того, чтобы зависеть от split (), напишите свой собственный анализатор, чтобы справиться с этой ситуацией.Пусть ваша грамматика обрабатывает все символы между парой "" или "как один токен.

...