Menu

#188 double quote on format give me 2 double quote

v1.0 (example)
closed-works-for-me
5
2018-12-20
2018-12-03
No

Hello, mi name is Juan Carlos, and I think that I found a small bug in the format attribute in the @CsvBindByName when I write a CSV file.

When I write this anotation in my JAVA class: @CsvBindByName (column = "nombre", format="\"%s\n")

The output is: ""bill""

If I choose another chart like single quote: @CsvBindByName (column = "nombre", format="'%s'")

The output is: "'bill'"

I think that is a bug.

Please forgive if is mistake from me.

I´m using your library to generate CSV, but I need the format feature because I need double quotes on string, and no quotes on number.

Regards,

Juan Carlos

Discussion

  • Juan Carlos Ballesteros

    Thanks in advance

     
  • Andrew Rucker Jones

    • assigned_to: Andrew Rucker Jones
     
  • Andrew Rucker Jones

    If I can reproduce the behavior you're describing, it's definitely a bug. I will take a look at it as soon as I can.

     
  • Andrew Rucker Jones

    Wait a minute: Let me get really straight on what behavior you're expecting. In your first example you have \"%s\n. That is, no closing quote. Yet one is added by the code, you say. What exactly would you expect the output to be?

    In the second example you have '%s'. The output you say you get from that looks exactly right to me. Are you expecting something else.

     
  • Juan Carlos Ballesteros

    In the first example only write one double quote to show you the problem.

    If I use this format: format="\"%s\""

    I have this out: ""bill""

    Thanks again

     
  • Andrew Rucker Jones

    Okay, now you've lost me. That's expected behavior. Perhaps it would be easiest if you could submit a failing test case.

     
  • Juan Carlos Ballesteros

    I´ll write a small example:

    Imagine this class:

    public class Subvencion
    {
    @CsvBindByName (column = "nombre", format="\"%s\"")
    private String nombre;
    @CsvBindByName
    private double importe;
    }

    And I have three objects:
    1. nombre="gasto1", importe=1000
    2. nombre="gasto2", importe=200
    3. nombre="gasto3", importe=400

    When I Write to a CSV I hope:

    "gasto1",1000
    "gasto2",200
    "gasto3",400

    But I have

    ""gasto1"",1000
    ""gasto2"",200
    ""gasto3"",400

    Please apologize me for the delay.

     

    Last edit: Juan Carlos Ballesteros 2018-12-19
  • Scott Conway

    Scott Conway - 2018-12-20

    Next time please try and send a failing JUnit test because the above example does not show us how you set up the BeanToCSV or any of the classes it used.

    Making alot of assumptions I was able to recreate your situation and it is not a bug.

    First I assumed that you are using the formats so you can control what gets quotes around it and what does not.

    As such I wrote the following test and it did indeed fail.

    public class BindQuoteTest {
    
    HeaderColumnNameMappingStrategy<Subvencion> minimalStrategy;
    StringReader reader;
    StringWriter writer;
    
    @Before
    public void setup() {
        minimalStrategy = new HeaderColumnNameMappingStrategy<>();
        minimalStrategy.setType(Subvencion.class);
        reader = new StringReader("nombre,importe\ngasto1,1000\ngasto2,200\ngasto3,400");
        writer = new StringWriter();
    }
    
    @Test
    public void dataFromBug() throws CsvDataTypeMismatchException, CsvRequiredFieldEmptyException {
        CsvToBean csvToBean = new CsvToBeanBuilder(reader)
                                            .withMappingStrategy(minimalStrategy)
                                            .build();
    
        List<Subvencion> list = csvToBean.parse();
    
        Subvencion sub1 = list.get(0);
    
        assertEquals("gasto1", sub1.getNombre());
        assertEquals(1000.0, sub1.getImporte(), 0.001);
    
        StatefulBeanToCsv beanToCsv = new StatefulBeanToCsvBuilder(writer)
                                        .withApplyQuotesToAll(false)
                                        .withQuotechar(CSVWriter.NO_QUOTE_CHARACTER)
                                        .build();
    
        beanToCsv.write(list.get(0));
    
        assertEquals("IMPORTE,NOMBRE\n1000.0,\"gasto1\"\n", writer.toString());
    }
    }
    

    But wait! If I said it was not a bug why does my test fail? The reason being is that passing a standard writer into the StatefulBeanToCsvBuilder a CSVWriter is created to handle all the writing. In the CSVWriter class the ESCAPE character is a double quote. So because the format added a double quote to the string even though we said there is no quote characters the code detects the double quote as an escape character and therefore prepends an escape character to it. Thus you get your double double quotes.

    There are a couple of ways around this. The first is to create an CSVParserWriter and pass in a RFC4180Parser. But the easiest way is just tell the builder you do not have an escape character.

        StatefulBeanToCsv beanToCsv = new StatefulBeanToCsvBuilder(writer)
                                        .withApplyQuotesToAll(false)
                                        .withQuotechar(CSVWriter.NO_QUOTE_CHARACTER)
                                        .withEscapechar(CSVWriter.NO_ESCAPE_CHARACTER)
                                        .build();
    

    Which is what I did and my test now passes.

    If this does not fix the situation please copy my unit test and modify it to match the situation you are having. It really makes it alot easier to diagnose the problem.

    Scott :)

     

    Last edit: Scott Conway 2018-12-20
  • Juan Carlos Ballesteros

    Now works, I have the expected CSV.

    Thanks a lot.

     
  • Scott Conway

    Scott Conway - 2018-12-20
    • status: open --> closed-works-for-me
     
  • Scott Conway

    Scott Conway - 2018-12-20

    Was able to get expected results by configuration.

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.