vibenazi
vibenazi

Reputation: 11

Surround CSV lines with double quotes/ create custom main method

I have to take a CSVReader IBM created and make changes that fit my requirements. I am new to java and not sure how to do any except for #1, my requirements are:

  1. take the CSV through the command line
  2. add a main method
  3. surround each line with double quotes
  4. output a new CSV

Ex. Input Jordan, Michael, J, ", 23
Ex. Output "Jordan, Michael, J, "", 23"

Background information: this program will be added into a shell script, the functionality is being added because the csv is corrupted if a single double quote is entered

Here is the code:

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

Upvotes: 1

Views: 1266

Answers (2)

vibenazi
vibenazi

Reputation: 11

Here is the full code, with all requirements met:

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

Upvotes: 0

minioim
minioim

Reputation: 858

If your only need is about escaping double quotes, a simple way to do it is not considering the CSV file as a CSV but as a simple text file.

first thing first: the main method in Java is quite simple. use this declaration:

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] ...
}

the main method will be automatically used by java if one is found in the called java class.

important point: main method MUST be public static and returning nothing as you can see here : Java spec, chapter 12

about your need, read each line from the file and replace it with the result of this function in a new file:

/**
 * 
 * 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;
}

to write your resulting file, you can use those informations :

how to write files line by line using java

Upvotes: 1

Related Questions