1

I am fairly new to python. Was following the suggestions from here trying to force a string to be output with a single set of double quotes (e.g., "my_string") but it always ends up being printed as such: """my_string"""

Any idea why?

I tried: '"' + my_string + '"' and f'"{self.args["name"]}"' and str(my_string) and "\"" + my_String + "\"" but same behavior:

"""my_string"""

Code snippet:

def print_out(self):
    self.args = {}
    self.args["name"] = 001
    self.bla = 1
    self.tra = 0
    self.val = 0.12445
    with open("my_file", "w") as fout:
          tsv = csv.writer(fout, delimiter="\t")
          tsv.writerow(["name", "bla", "tra", "hehe"])
          tsv.writerow(
                    [f'"{self.args["name"]}"', self.bla, self.tra, round(self.val, 2)]
          )

In the above example, the self.args["name"] is printed as """001"""

Thanks

Marius
  • 990
  • 1
  • 14
  • 34
  • 4
    `print("Hello")` should appear on the screen as just `Hello`, with no quote marks at all, so you must be doing something unusual. Show us the actual code you're using. Otherwise we're only guessing at the cause. – John Gordon Mar 12 '20 at 15:35
  • 3
    How are you printing it? Can you provide a [Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example)? – jordanm Mar 12 '20 at 15:36
  • sure, i'll edit my question – Marius Mar 12 '20 at 15:41
  • 1
    The obvious answer is that it's not an artifact of printing; `my_string` _actually contains_ the quote marks. – John Gordon Mar 12 '20 at 15:43
  • 1
    `csv.writer` is adding the extra quotes. – chepner Mar 12 '20 at 15:49
  • but if I do not add any quotes and I let it be `self.args["name"]` prints it as `001`. the problem is that later down the processing pipeline, another "smart" text parser converts it into a number (e.g., `1`) and it is actually a string – Marius Mar 12 '20 at 15:50
  • 2
    The default dialect uses `"` to quote a field that contains either the field delimiter, or the quote character. A quote character is escaped, again by default, by doubling it. – chepner Mar 12 '20 at 15:51
  • @JohnGordon thanks for your comment. not true though. sorry you did not have an example snippet – Marius Mar 12 '20 at 15:52
  • @chepner so then what is the proper way to feed it to the csv writer to have it output with only one set of double quotes? – Marius Mar 12 '20 at 15:52
  • 2
    The question now is, why are you adding the quotes around that field yourself? – chepner Mar 12 '20 at 15:52
  • @chepner please see above comment. down the line another parser converts it into a numeral instead of leaving it as a string, which it should remain as – Marius Mar 12 '20 at 15:53
  • Another CSV parser? You could try adding `quoting=csv.QUOTE_NONE` to the call to `csv.writer`, but that may have other unintended consequences depending on the other data you are writing to the file. – chepner Mar 12 '20 at 15:55
  • What Python version are you using? ``001`` is a syntax error. – MisterMiyagi Mar 12 '20 at 15:56
  • @chepner no, a parser that converts it to JSON, but then the expected `001` key becomes `1` and then trying to retrieve it ends up in an error. i'm currently trying your suggestion qith `QUOTE_NONE` – Marius Mar 12 '20 at 15:57
  • Note that if ``001`` becomes ``1``, perhaps you meant to set it to ``"001"`` from the start (a literal string, not a literal in a string like ``'"001"'``). Does that fix your problem? – MisterMiyagi Mar 12 '20 at 15:59
  • @chepner that results in an error `_csv.Error: need to escape, but no escapechar set ` will try to set it via `csv.register_dialect` – Marius Mar 12 '20 at 16:02
  • You should really let `csv.writer` escape the double quotes, then adjust the *other* parser to correctly parse the CSV file before trying to output JSON. – chepner Mar 12 '20 at 16:03
  • 1
    That is, `"001"` is the data you want to store, and `"""001"""` is the default way to specify that value in a CSV file. You should start by reading the documentation for the `csv` module regarding dialects, and ask a new question if you have trouble creating the CSV file or parsing it. – chepner Mar 12 '20 at 16:04
  • thing is that the other parser is in a third party tool that i want to avoid modifying, due to licensing. so trying it "manually" to put quotes around the string, solves it. don't get it why is so difficult to add a freaking set of double quotes to a string in python :D – Marius Mar 12 '20 at 16:05
  • 1
    It's not difficult at all. You are trying to add a quoted string to a CSV file, which requires you to understand how CSV files work. The same would be true whether or not you were using Python. – chepner Mar 12 '20 at 16:06
  • so then why the `csv.writer` outputs my string without any quotes to start with? or any of the values passed to it to that matter? – Marius Mar 12 '20 at 16:08

2 Answers2

6

CSV files come in many different dialects. In their simplest form, they are just a list of strings, separated by a delimiter. In this case, you are using a tab.

The problems start when you want a value that contains a delimiter; then you have to escape the tab in some way to prevent a parser from treating it as such. One way of doing that is to quote the entire field.

But now, how do you include a quote in the value of a field? By default, you quote the field and escape the literal quotes by doubling them.

So, "001" becomes """001""" because the value "001" has to be quoted, and the literal " each gets replaced by "". A parser (using this default dialect) would see "..." and strip the outer most quotes, then replace each remaining pair of quotes with a single quote to get "001" back from """001""".

There appear to be a number of ways to disable quoting of double quotes, and which one you need may depend on the other kind of data you are using. One simple way is to simply set the quotechar argument to None when creating the CSV writer.

      tsv = csv.writer(fout, delimiter="\t", quotechar=None)

See Dialects and Formatting Parameters for more information about how exactly data is quoted and/or escaped in a CSV file.


A demonstration:

>>> f = csv.writer(sys.stdout, delimiter="\t")
>>> f.writerow(["001", 3])
001 3
7
>>> f.writerow(['"001"', 3])
"""001"""   3
13
>>> f = csv.writer(sys.stdout, delimiter="\t", quotechar=None)
>>> f.writerow(["001", 3])
001 3
7
>>> f.writerow(['"001"', 3])
"001"   3
9

(Each call to f.writerow shows the data written to standard output, followed by its return value.)

chepner
  • 497,756
  • 71
  • 530
  • 681
  • thanks for all the details. it does output already with no quotes around the fields, so setting `quotechar = None` has no effect. even if I set `quotechar = '"'` it still exports with no quotes. ehh.. I'll play with it and figure out something eventually. thanks for your time – Marius Mar 12 '20 at 16:47
  • OK. apparently if I set my string to be `'"' + self.args["name"] + '"'` in combination with `quotechar=None` as parameter to the `csv.writer` produces the expected output. probably that's what you actually meant in your answer @chepner. thanks once again – Marius Mar 12 '20 at 16:55
0
f'"{self.args["name"]}"'

That string contains embedded double quotes, so you're telling csv to write the literal value "1".

However, csv is smart enough to know that if it wrote just "1" in the file, then future readers of the file might get confused -- is that supposed to be a plain 1 and it just happens to have quotes around it, or is it literally the value "1"?

Since you told csv to write a literal "1", csv uses triple quotes as special syntax.

Presumably you meant to use f'{self.args["name"]}' instead, without the extra layer of quoting.

John Gordon
  • 29,573
  • 7
  • 33
  • 58
  • the string itself is `001` and I want it exported as `"001"` via a `csv.writer` – Marius Mar 12 '20 at 16:06
  • well i'm trying to understand why by default it uses **no quotes at all** and when I want to add **one set of quotes** it puts three as a "special syntax" as you call it – Marius Mar 12 '20 at 16:11
  • using `f'{self.args["name"]}'` has no different effect. still outputs `"""001"""` – Marius Mar 12 '20 at 16:13
  • 1
    That's not possible with the code as shown. Show us the actual definition of `self.args` that you're using. (`001` is not a legal value, so I know that code is incorrect.) – John Gordon Mar 12 '20 at 16:14
  • the code is a lot too complex to put it all here. I will make sure that the actual input string does not contain any quotes.. which I am pretty sure it doesn't because it is not output within quotes to start with.. but anyhow. will try to figure it out. thanks for your suggestions and your time. the pipeline consists of a mix of several programming languages put together so giving you a literally equivalent working example would be too complicated for you to run. thanks tho – Marius Mar 12 '20 at 16:20
  • 1
    Even if the real code is too complex, you can make a toy program that demonstrates the behavior. – John Gordon Mar 12 '20 at 16:26
  • i'll try other suggestions instead of spending time to write a toy program. again, if I just feed `self.args["name"]` to the `csv.writer` it output the string `001` without any quotes. if I am adding quotes to the string, it outputs three sets of double quotes. why is the default behavior to output no quotes at all around strings.. i have no idea. will try to add them by default and see how the downstream parser deals with it – Marius Mar 12 '20 at 16:32
  • i got it working as it should now. see comment for the above answer. if I had hours and hours to spend, I would make a toy example for each little case i come across. unfortunately, there are only 24h in a day and I like to get things done. i see that you guys up-voted each other's comments enough, so hope you're fine with me not up-voting your answer as it was pretty much off and with too many assumptions behind. thanks again – Marius Mar 12 '20 at 17:04