Menu

#123 separator does not escape when quotechar is NO_QUOTE_CHARACTER

v1.0 (example)
closed-fixed
None
1
2015-12-25
2015-12-06
Haim
No

I have a simular issue to http://stackoverflow.com/questions/32644150/opencsv-reading-file-with-escaped-separator. I need to escape the delimiter but I am not using quotechar.

I am not sure if this was done deliberately but it looks like the fix is very simple

public class CSVWriter
...
/
* Appends the character to the StringBuilder adding the escape character if
* needed.
*
* @param sb
* - StringBuffer holding the processed character.
* @param nextChar
* - character to process
*/
private void processCharacter(StringBuilder sb, char nextChar) {
if (escapechar != NO_ESCAPE_CHARACTER && (
nextChar == quotechar** || nextChar == escapechar || nextChar == separator)) {
sb.append(escapechar).append(nextChar);
} else {
sb.append(nextChar);
}
}

Discussion

  • Scott Conway

    Scott Conway - 2015-12-20

    Hello Haim - sorry it has been so long to respond but work and family have kept me busy.

    Please make sure you are using the 3.6 openCSV. If you are then please check the unit test I created to try and recreate your issue. This test is passing when according to what you are saying it should fail so if I am misunderstanding the problem please let me know.

    @Test
    public void issue123SeparatorEscapedWhenQuoteIsNoQuoteChar() {
    String[] header = {"Foo", "Bar", "baz"};
    String[] value = {"v1", "v2" + CSVWriter.DEFAULT_ESCAPE_CHARACTER +"v2a", "v3"};

      List<String[]> lines = new ArrayList<String[]>();
      lines.add(header);
      lines.add(value);
      StringWriter sw = new StringWriter();
      CSVWriter writer = new CSVWriter(sw, CSVWriter.DEFAULT_SEPARATOR, CSVWriter.NO_QUOTE_CHARACTER, CSVWriter.DEFAULT_ESCAPE_CHARACTER);
      writer.writeAll(lines);
    
      String result = sw.toString();
      assertNotNull(result);
      assertEquals("Foo,Bar,baz\nv1,v2"+CSVWriter.DEFAULT_ESCAPE_CHARACTER+CSVWriter.DEFAULT_ESCAPE_CHARACTER+"v2a,v3\n", result);
    

    }

     
  • Scott Conway

    Scott Conway - 2015-12-20
    • assigned_to: Scott Conway
     
  • Haim

    Haim - 2015-12-24

    I cloned Release-3.6 branch and run the flowing modification of your tests.
    For example in the secound test I expected the data in the secound cell v2\v2a,v2b
    to be v2\v2a\,v2b

      @Test
       public void issue123SeparatorEscapedWhenQuoteIsNoQuoteChar() {
       String[] header = {"Foo", "Bar", "baz"};
       String[] value = {"v1", "v2" + CSVWriter.DEFAULT_ESCAPE_CHARACTER +"v2a"+CSVWriter.DEFAULT_SEPARATOR+"v2b", "v3"};
         List<String[]> lines = new ArrayList<String[]>();
         lines.add(header);
         lines.add(value);
         StringWriter sw = new StringWriter();
         CSVWriter writer = new CSVWriter(sw, CSVWriter.DEFAULT_SEPARATOR, CSVWriter.NO_QUOTE_CHARACTER, CSVWriter.DEFAULT_ESCAPE_CHARACTER);
         writer.writeAll(lines);
    
         String result = sw.toString();
         assertNotNull(result);
         assertEquals("Foo,Bar,baz\nv1,v2"+CSVWriter.DEFAULT_ESCAPE_CHARACTER+CSVWriter.DEFAULT_ESCAPE_CHARACTER+"v2a"+CSVWriter.DEFAULT_ESCAPE_CHARACTER+CSVWriter.DEFAULT_SEPARATOR+"v2b,v3\n", result);
       }
    

    org.junit.ComparisonFailure: expected:<...o,Bar,baz
    v1,v2""v2a["],v2b,v3

    but was:<...o,Bar,baz
    v1,v2""v2a[],v2b,v3

      @Test
       public void issue123SeparatorEscapedWhenQuoteIsNoQuoteCharSpecifingNoneDefaultEscapeChar() {
       String[] header = {"Foo", "Bar", "baz"};
       char escapeCharacter = '\\';
       String[] value = {"v1", "v2" + escapeCharacter +"v2a"+CSVWriter.DEFAULT_SEPARATOR+"v2b", "v3"};
         List<String[]> lines = new ArrayList<String[]>();
         lines.add(header);
         lines.add(value);
         StringWriter sw = new StringWriter();
         CSVWriter writer = new CSVWriter(sw, CSVWriter.DEFAULT_SEPARATOR, CSVWriter.NO_QUOTE_CHARACTER, escapeCharacter);
         writer.writeAll(lines);
    
         String result = sw.toString();
         assertNotNull(result);
         assertEquals("Foo,Bar,baz\nv1,v2"+escapeCharacter+escapeCharacter+"v2a"+escapeCharacter+CSVWriter.DEFAULT_SEPARATOR+"v2b,v3\n", result);
       }
    

    org.junit.ComparisonFailure: expected:<...o,Bar,baz
    v1,v2\v2a[],v2b,v3

    but was:<...o,Bar,baz
    v1,v2\v2a[],v2b,v

     

    Last edit: Haim 2015-12-24
  • Scott Conway

    Scott Conway - 2015-12-25
    • status: open --> closed-fixed
     
  • Scott Conway

    Scott Conway - 2015-12-25

    Thanks for the sample test! That allowed me to pin down the issue and come up with a fix.

    I had to expand on your suggestion because if we do have a quote character defined we do not need or want to escape the separator character. So I ended up doing this:

    private void processCharacter(StringBuilder sb, char nextChar) {
    if (escapechar != NO_ESCAPE_CHARACTER && checkCharactersToEscape(nextChar)) {
    sb.append(escapechar).append(nextChar);
    } else {
    sb.append(nextChar);
    }
    }

    private boolean checkCharactersToEscape(char nextChar) {
    return quotechar == NO_QUOTE_CHARACTER ?
    (nextChar == quotechar || nextChar == escapechar || nextChar == separator)
    : (nextChar == quotechar || nextChar == escapechar);
    }

    I have merged this into trunk and will be in the 3.7 release.

     

Log in to post a comment.