【问题标题】:Surround CSV lines with double quotes/ create custom main method用双引号括住 CSV 行/创建自定义主方法
【发布时间】:2016-07-08 20:52:54
【问题描述】:

我必须使用 IBM 创建的 CSVReader 并根据我的要求进行更改。我是 java 新手,除了#1 不知道怎么做,我的要求是:

  1. 通过命令行获取 CSV
  2. 添加主方法
  3. 用双引号将每一行括起来
  4. 输出一个新的 CSV

例如。输入 乔丹,迈克尔,J,“,23
前任。输出 "乔丹,迈克尔,J,"",23"

背景信息:此程序将被添加到 shell 脚本中,正在添加功能,因为如果输入单个双引号,csv 会损坏

代码如下:

package Scripts;

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

public class CSVReader 
{
    private BufferedReader br;
    private boolean hasNext = true;
    private static char separator = ' ';
    private static char quotechar = ' '; 

    public static final char DEFAULT_SEPARATOR = ',';
    public static final char DEFAULT_QUOTE_CHARACTER = '"';

    public static void main(final String[] args) throws IOException {
    final String csvFile = args[0];
    final ArrayList<String[]> allElements = new ArrayList<String[]>();
    final CSVReader csvReader = new CSVReader(br, separator, quotechar, csvFile);
    csvTransformer.readAll();
    csvTransformer.close();
}

    public CSVReader(final Reader reader) throws FileNotFoundException {
        this(reader, DEFAULT_SEPARATOR);
    }

    public CSVReader(final Reader reader, final char separator) throws FileNotFoundException {
        this(reader, separator, DEFAULT_QUOTE_CHARACTER, null);
    }
    public CSVReader(final Reader reader, final char separator, final char quotechar, final String csvFile) throws FileNotFoundException {
        CSVTransformer.br = new BufferedReader(new FileReader(csvFile));
        this.separator = separator;
        this.quotechar = quotechar;
    }


/**
 * Reads the entire file into a List with each element being a String[] of tokens.
 * 
 * return a List of String[], with each String[] representing a line of the file.
 */
    public List readAll() throws IOException 
    {
        List allElements = new ArrayList();
        while (hasNext) 
        {
            String[] nextLineAsTokens = readNext();
            if (nextLineAsTokens != null) 
                allElements.add(nextLineAsTokens);
        }
        return allElements;
    }

/**
 * Reads the next line from the buffer and converts to a string array.
 * 
 * return a string array with each comma-separated element as a separate entry.
 */
    public String[] readNext() throws IOException {
        String nextLine = getNextLine();
        return hasNext ? parseLine(nextLine) : null;
    }

/**
 * Reads the next line from the file.
 * 
 * return the next line from the file without trailing newline
 */
    private String getNextLine() throws IOException {
        String nextLine = br.readLine();
        if (nextLine == null) {
            hasNext = false;
        }
        return hasNext ? nextLine : null;
    }

/**
 * Parses an incoming String and returns an array of elements.
 * 
 * @param nextLine
 *            the string to parse
 * @return the comma-tokenized list of elements, or null if nextLine is null
 * @throws IOException if bad things happen during the read
 */
    private String[] parseLine(String nextLine) throws IOException {
        if (nextLine == null) {
            return null;
        }
        List tokensOnThisLine = new ArrayList();
        StringBuffer sb = new StringBuffer();
        boolean inQuotes = false;
        do {
            if (inQuotes) {
            // continuing a quoted section, reappend newline
                sb.append("\n");
                nextLine = getNextLine();
                if (nextLine == null)
                break;
            }
            for (int i = 0; i < nextLine.length(); i++) {
                char c = nextLine.charAt(i);
                if (c == quotechar) {
                // this gets complex... the quote may end a quoted block, or escape another quote.
                // do a 1-char lookahead:
                if(inQuotes)  // we are in quotes, therefore there can be escaped quotes in here.
                        && nextLine.length() > (i+1)  // there is indeed another character to check.
                        && nextLine.charAt(i+1) == quotechar )
                    { // ..and that char. is a quote also.
                    // we have two quote chars in a row == one quote char, so consume them both and
                    // put one on the token. we do *not* exit the quoted text.
                        sb.append(nextLine.charAt(i+1));
                        i++;
                    }
                    else
                    {
                        inQuotes = !inQuotes;
                    }
                }
                else if (c == separator && !inQuotes) {
                    tokensOnThisLine.add(sb.toString());
                    sb = new StringBuffer(); // start work on next token
                }
                else {
                    sb.append(c);
                }
            }
        } while (inQuotes);
        tokensOnThisLine.add(sb.toString());
        return (String[]) tokensOnThisLine.toArray(new String[0]);
    }

    public void close() throws IOException {
        br.close();
    }
}
on

【问题讨论】:

    标签: java csv parsing escaping double-quotes


    【解决方案1】:

    如果您只需要转义双引号,那么一种简单的方法就是不将 CSV 文件视为 CSV,而是将其视为简单的文本文件。

    第一件事:Java 中的 main 方法非常简单。使用这个声明:

    public static void main(String... args){
        //do your stuff
        // args is a String array containing parameters passed to your script, like your file. to get the first param, use args[0] , for the second it's args[1] ...
    }
    

    如果在被调用的java类中找到main方法,java将自动使用。

    重点:main 方法必须是 public static 并且不返回任何内容 正如你在这里看到的:Java spec, chapter 12

    关于您的需要,从文件中读取每一行并将其替换为新文件中此函数的结果:

    /**
     * 
     * replace quotes in a line and append/prepend quotes to the line and return it
     * 
     */
    private static String correctQuotesInLine(String nextLine) {
        if (nextLine == null) {
            return null;
        }
    
        //replace any single " in line
        String result = nextLine.replaceAll("\"", "\"\"");
        //prepend and append line with quotes
         result = "\"" + result + "\"";
    
    
        return result;
    }
    

    要编写生成的文件,您可以使用这些信息:

    how to write files line by line using java

    【讨论】:

    • 我很抱歉不清楚,我对 main 方法感到困惑,因为我得到了 3 个不同的构造函数,并且不清楚使用哪个构造函数,以及何时应该将值传递给它们主要。
    • 我不确定你问的是什么。您可以根据需要使用任何现有的构造函数。第一个构造函数将创建一个带有默认分隔符和默认引号字符的 CSVReader。如果要更改它,请使用第三个并指定游览分隔符/引号作为参数。也许尝试编写一些代码并将其发布在这里。更容易理解您的需求。
    • 基本上,“this”代表您的实例。这不是强制性的,但在构造函数中设置变量时避免混淆。关于构造函数,这里的“真正”是第三个。第二个使用默认的 quotechar 参数调用第三个。第一个使用默认分隔符参数调用第二个(调用第三个)的第一个相同。然后构造函数简单地设置变量。
    • 好的。根据该信息,我将 BufferedReader 设置在第三个构造函数中,现在得到一个 NullPointerException。关于如何传递该文件的任何想法,都必须来自命令行。
    • 我会将路径作为参数传递给您的 main 方法,然后从那里检索文件
    【解决方案2】:

    这里是满足所有要求的完整代码:

    package Scripts;
    
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.File;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.Reader;
    import java.util.ArrayList;
    import java.util.List;
    
    public class CSVReader {
    
    private static BufferedReader br;
    private static BufferedWriter writer;
    private static FileWriter fileWriter;
    private boolean hasNext = true;
    private static char separator = ' ';
    private static char quotechar = ' ';
    static List<String[]> allElements;
    
    public static final char DEFAULT_SEPARATOR = ',';
    public static final char DEFAULT_QUOTE_CHARACTER = '"';
    
    public static void main(final String[] args) throws IOException {
        final String csvFile = args[0];
        final File newCSV = new File("newCSV.csv");
        final CSVReader csvTransformer = new CSVReader(br, separator, quotechar, csvFile, newCSV);
        csvTransformer.readAll();
        csvTransformer.close();
    }
    
    public CSVReader(final Reader reader) throws IOException {
        this(reader, DEFAULT_SEPARATOR);
    }
    
    public CSVReader(final Reader reader, final char separator) throws IOException {
        this(reader, separator, DEFAULT_QUOTE_CHARACTER, null, null);
    }
    
    public CSVReader(final Reader reader, final char separator, final char quotechar, final String csvFile,
            final File newCSV) throws IOException {
        CSVReader.br = new BufferedReader(new FileReader(csvFile));
        CSVReader.separator = separator;
        CSVReader.quotechar = quotechar;
        CSVReader.fileWriter = new FileWriter(newCSV.getAbsoluteFile());
        CSVReader.writer = new BufferedWriter(fileWriter);
    }
    
    /**
     * Reads the entire file into a List with each element being a String[] of tokens.
     *
     * return a List of String[], with each String[] representing a line of the file.
     */
    
    public List<String[]> readAll() throws IOException {
        final List<String[]> allElements = new ArrayList<String[]>();
        while (hasNext) {
            final String[] nextLineAsTokens = readNext();
            if (nextLineAsTokens != null) {
                allElements.add(nextLineAsTokens);
            }
        }
        return allElements;
    }
    
    /**
     * Reads the next line from the buffer and converts to a string array.
     *
     * return a string array with each comma-separated element as a separate entry.
     */
    
    public String[] readNext() throws IOException {
        final String nextLine = getNextLine();
        return hasNext ? parseLine(nextLine) : null;
    }
    
    /**
     * Reads the next line from the file.
     *
     * return the next line from the file without trailing newline
     */
    
    private String getNextLine() throws IOException {
        final String nextLine = br.readLine();
        if (nextLine == null) {
            hasNext = false;
        }
        return hasNext ? nextLine : null;
    }
    
    /**
     * Parses an incoming String and returns an array of elements & adds results to CSV.
     *
     * @param nextLine
     *            the string to parse
     * @return the comma-tokenized list of elements, or null if nextLine is null
     * @throws IOException
     *             if bad things happen during the read
     */
    
    private String[] parseLine(final String nextLine) throws IOException {
    
        if (nextLine == null) {
            return null;
        }
        final List<String> tokensOnThisLine = new ArrayList<String>();
        String result = nextLine.replaceAll("\"", "\"\"");
        result = "\"" + result + "\"";
        tokensOnThisLine.add(result.toString());
        writer.write(result);
        writer.write("\n");
        return tokensOnThisLine.toArray(new String[0]);
    }
    
    public void close() throws IOException {
        br.close();
        writer.close();
    }
    } // end
    

    【讨论】:

      猜你喜欢
      • 2013-07-28
      • 2012-03-20
      • 2023-03-25
      • 2020-02-21
      • 1970-01-01
      • 1970-01-01
      • 2014-08-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多