LambdaLabTM
Computer Science · Class 12 · CSV Files
CSV filesdelimiter⏱️ 12 min read

Choosing the Separator

The C in CSV stands for comma, and it has misled a great many students. The comma is what the csv module uses when you do not say otherwise — a default, not a rule. Any single character can be the separator, and one argument is how you pick it.

1The delimiter argument

csv.writer(f, delimiter='|')

Goes after the file, on csv.writer() and csv.reader() alike. Leave it out and you get ','.

pipe_write.py
import csv

f = open('marks_pipe.csv', 'w', newline='')
w = csv.writer(f, delimiter='|')

w.writerow(['Roll', 'Name', 'Marks'])
w.writerow([1, 'Ravi', 78])
w.writerow([2, 'Meera', 91])

f.close()

print(open('marks_pipe.csv', newline='').read())
Output
Roll|Name|Marks
1|Ravi|78
2|Meera|91

Nothing else about the program changed. The rows are the same lists, the methods are the same methods — only the character between the values is different.

2Why anyone would want a different one

Semicolon — ;

Much of Europe writes twelve and a half rupees as 12,50. A comma is already the decimal point there, so it cannot also be the separator. Open a European CSV in Excel and it is almost always semicolons.

Pipe — |

Almost never appears inside real data, so no value ever needs quoting. Common when the values are addresses or sentences.

Tab — \t

Gives you a TSV file. The columns line up when you open it in a plain editor, which makes it much easier to read by eye.

Anything else

A colon, a hash, a space. If it is one character, the module will use it — though your reader has to know.

The semicolon case is the one worth seeing, because the file would be unreadable any other way:

euro.py
import csv

f = open('euro.csv', 'w', newline='')
w = csv.writer(f, delimiter=';')
w.writerow(['Item', 'Price'])
w.writerow(['Pen', '12,50'])
f.close()

print(open('euro.csv', newline='').read())

f = open('euro.csv', 'r', newline='')
for row in csv.reader(f, delimiter=';'):
    print(row)
f.close()
Output
Item;Price
Pen;12,50

['Item', 'Price']
['Pen', '12,50']

The comma inside 12,50 is left completely alone, because on this file a comma is not a separator — a semicolon is.

3Both sides have to be told

The delimiter is not written down anywhere in the file. There is no header saying “this file uses pipes” — there are just characters. So the reader has to be told the same thing the writer was told. Here is the pipe file from section 1, read with the default:

pipe_wrong.py
import csv

f = open('marks_pipe.csv', 'r', newline='')
for row in csv.reader(f):
    print(row)
f.close()
Output
['Roll|Name|Marks']
['1|Ravi|78']
['2|Meera|91']
No error — just one value per row
The reader looked for commas, found none, and concluded that each line holds a single value. row[0] is the whole line and row[1] raises IndexError: list index out of range somewhere further down. When a CSV reads back as one long string per row, this is the first thing to check.

Told the right separator, the same file reads perfectly:

pipe_right.py
import csv

f = open('marks_pipe.csv', 'r', newline='')
for row in csv.reader(f, delimiter='|'):
    print(row)
f.close()
Output
['Roll', 'Name', 'Marks']
['1', 'Ravi', '78']
['2', 'Meera', '91']
csv.reader(f, delimiter='|')

The same argument, in the same position, on the reader. Whatever the writer was told, the reader must be told too.

the file did not change

Both runs above read the identical file off the disk. Only the instruction differed — which is what makes the delimiter a setting rather than part of the data.

4Set both knobs yourself

🔀 Two knobs, one file

Set the separator the writer uses, then set the one the reader is told to expect. They do not have to agree — and nothing warns you when they do not.

1 · writing
w = csv.writer(f, delimiter='|')
marks.csv on the disk
Roll|Name|Marks
1|Ravi|78
2|Meera|91
2 · reading it back
for row in csv.reader(f):
what each row comes back as
['Roll|Name|Marks']1 value
['1|Ravi|78']1 value
['2|Meera|91']1 value

They disagree. The reader hunted for commas, found none, and handed back the whole line as a single value. No error, no warning — just row[1] raising IndexError somewhere further down your program.

5Exactly one character

A separator is a single character. Two is not allowed, and this one does stop the program:

two_chars.py
import csv

f = open('x.csv', 'w', newline='')
w = csv.writer(f, delimiter='||')
Output
Traceback (most recent call last):
  File "two_chars.py", line 4, in <module>
    w = csv.writer(f, delimiter='||')
TypeError: "delimiter" must be a 1-character string
Note
'\t' is fine, because a tab is one character — the backslash and the t are how you type it, not what it is. The same goes for any escape sequence.

6Quoting follows whichever character you chose

The writer quotes a value when that value contains the separator. Change the separator and you change which values need quoting — the same row, written twice:

quoting.py
import csv

row = ['Sharma, Kumar and Sons', 'Delhi']

f = open('shops1.csv', 'w', newline='')
csv.writer(f).writerow(row)
f.close()

f = open('shops2.csv', 'w', newline='')
csv.writer(f, delimiter='|').writerow(row)
f.close()

print(open('shops1.csv', newline='').read())
print(open('shops2.csv', newline='').read())
Output
"Sharma, Kumar and Sons",Delhi

Sharma, Kumar and Sons|Delhi

With commas separating, the name needed quotes. With pipes separating, the comma inside the name is just an ordinary character and no quotes were needed. Either file reads back as the same two values — provided the reader is told which separator was used.

7It is still called a CSV file

A file separated by semicolons is still a CSV file, and is still normally named .csv. The name stopped being literal a long time ago — people use it for the whole family of “one record per line, values separated by something” files. Tab-separated files are the one common exception: those are often named .tsv instead.

8Try every separator on one file

delimiter_playground.py

9Recap

Let's Recap!
What happens
delimiter left outthe comma is used — that is the default
delimiter='|' on both sidesthe file uses pipes and reads back correctly
delimiter='|' on the writer onlyeach row reads back as one long value, with no error
delimiter='||'TypeError: "delimiter" must be a 1-character string
delimiter='\t'a tab — one character, so perfectly legal. Usually named .tsv
a value containing the separatorthe writer wraps that value in quotes automatically
The comma is a default

Not part of the format. csv.writer(f) and csv.writer(f, delimiter=',') are the same call.

Any single character

Semicolon, pipe, tab, colon. Two characters raises TypeError.

The file does not record it

Nothing in a CSV says which separator it uses. You have to know, or look at the file.

Tell the reader too

The commonest mistake. A mismatch gives no error — just one value per row.

Why bother

Where the comma is the decimal point, or where the values themselves are full of commas.

Still a .csv

The extension does not change with the separator. Tab-separated files are often .tsv.

✍️ Now write these yourself
  1. 1

    Write the same three rows four times, with ',', ';', '|' and '\t', and open all four in Notepad.

    Hint · Same values, four different-looking files.

  2. 2

    Write with a semicolon and read with the default. Count the values in each row.

    Hint · One. And Python said nothing at all.

  3. 3

    Try delimiter='::' and read the error.

    Hint · Must be a 1-character string.

  4. 4

    Write a value containing a pipe into a pipe-separated file, then open the file.

    Hint · Quotes. The rule follows whichever separator you chose.

Quick Check

What separator does csv.writer(f) use when you do not say?

Quick Check

You wrote a file with delimiter='|' and read it back with csv.reader(f). What happens?

Quick Check

Why do many European CSV files use semicolons?

Quick Check

Is delimiter='||' allowed?