fileformer
search⌘KtranslateENexpand_moreupload_fileConvert
Converters8 file families · 44 direct conversions
What changes in a conversionarrow_forward
home / developer / csv

Convert CSV Document Free

CSV has a spec. Almost nobody follows the same one.

RFC 4180 says: commas between fields, CRLF between records, double quotes around fields that contain either, and a quote inside a quoted field written twice. Real files use semicolons, tabs, backslashes, stray quotes and whatever encoding the exporting machine liked. This page reads a file character by character with a state machine, guesses its dialect, profiles every column, flags what a spreadsheet will silently change, and shows five parsers disagreeing about the same bytes.

folder_openOpen .csv / .tsvClean RFC 4180Messy real-world exportEuropean, semicolons, 1252
orders-export.csv: LF, ragged rows, stray and backslash quotes, a blank line, an unterminated quote, Excel bait
the RFC 4180 state machine, one character at a timefirst 220 characters · delimiter “,”
order_id,sku,postcode,qty,date,customer,comment↵1001,MARCH1,02134,3,03/04/2026,"Smith,·J",ok↵1002,1E5,90210,1,13/04/2026,·"Lee,·K",spaces·before·the·quote↵1003,SEPT2,00501,2,4-5,Ana·"the·boss"·Ruiz,bare·quotes↵1004,AB-77
unquoted field textdelimiter: field endsrecord endsquote: opens, closes or escapesinside quotesnewline kept inside quoteserror: quote where none may be
dialect sniffing · fields per row under each candidate delimiter
,7 fields in 50% of 8 rows · 4 different countschosen
;1 fields in 100% of 9 rowsscore 0.00
TAB1 fields in 100% of 9 rowsscore 0.00
|1 fields in 100% of 9 rowsscore 0.00
encodingUTF-8No BOM: Excel on Windows will assume the system code page and garble non-ASCII text.
delimiter“,”Sniffed from consistency of field counts.
line endingsLFRFC 4180 says CRLF; LF is accepted by every mainstream reader.
records9Ends with a newline. Modal width 7 fields.
headerlikelyFirst row is all distinct text. CSV has no way to say so (except header=present in the MIME type).
quote char"Fields quoted: 5.

Parsed with the sniffed dialect

9 records · showing 9 · amber rows have the wrong field count
#order_idskupostcodeqtydatecustomercommentL21001MARCH102134303/04/2026Smith, JokL310021E590210113/04/2026·"Lee·K"spaces before the quoteL41003SEPT20050124-5Ana "the boss" Ruizbare quotesL51004AB-771011552026-04-14O\Neil"backslash escapeL6L71005ZX-9411111111111111112026-04-15=HYPERLINK("http://evil.example"Click)formulaL81006QQ-17500122026-04-16MüllerextrafieldshereL91007QQ-2100012026-04-17unterminated,never closed1008,QQ-3,2000,1,2026-04-18,Late,row
column profile · and what a spreadsheet does on open
order_idinteger · mixed
“1001” “1002” “1003” “1004”
skutext · mixed
“MARCH1” “1E5” “SEPT2” “AB-77”“MARCH1” is turned into a date on open (the reason 27 human genes were renamed in 2020).
postcodeinteger · mixed
“02134” “90210” “00501” “10115”Excel stores “02134” as the number 2134: leading zeros vanish (postcodes, IDs, phone numbers).
qtyinteger
“3” “1” “2” “5”
dateISO date · mixed
“03/04/2026” “13/04/2026” “4-5” “2026-04-14”“03/04/2026” is a different day in UK and US Excel, and becomes a date serial either way.
customertext · mixed
“Smith, J” “ "Lee” “Ana "the boss" Ruiz” “O\Neil"”“=HYPERLINK("http://evil.example"” starts with a formula character: spreadsheets execute it (CSV injection).
commenttext
“ok” “ K"” “bare quotes” “backslash escape”
strict RFC 4180 check
errorLine 3, col 30: bare quote inside an unquoted field.RFC 4180 only allows quotes around a whole field. Lenient readers keep it as a literal character.
errorLine 3, col 37: bare quote inside an unquoted field.RFC 4180 only allows quotes around a whole field. Lenient readers keep it as a literal character.
errorLine 4, col 28: bare quote inside an unquoted field.RFC 4180 only allows quotes around a whole field. Lenient readers keep it as a literal character.
errorLine 4, col 37: bare quote inside an unquoted field.RFC 4180 only allows quotes around a whole field. Lenient readers keep it as a literal character.
errorLine 5, col 35: text after a closing quote.Something follows the closing quote; readers disagree on whether to keep it.
errorLine 5, col 39: bare quote inside an unquoted field.RFC 4180 only allows quotes around a whole field. Lenient readers keep it as a literal character.
error5 record(s) with a different field count.Lines 3 (8), 6 (1), 7 (8), 8 (9), 9 (6). RFC 4180: every record should have the same number of fields.
info1 blank line(s).Strictly a record with one empty field; pandas skips them, Python csv returns an empty list, Excel shows an empty row.
check_circle1 record(s) with line breaks inside a quoted field.Correct CSV, but anything that reads line by line (grep, wc -l, naive splits) miscounts records.
info1 record(s) with spaces around values.RFC 4180: spaces are part of the field. Some readers trim them; joins on those columns then fail.
infoLF line endings.Not what the RFC says, but universally read.
error1 cell(s) start with = + − @.Opening this in a spreadsheet runs them as formulas. Defuse them in the writer below.
parser disagreement lab

Same bytes, five readings

Each column below is a real parser written here with one behaviour switched: splitting lines on commas (what a quick script does), strict RFC 4180, skipping spaces after a delimiter (Python’s skipinitialspace), backslash escapes (MySQL’s default ESCAPED BY), and dropping blank lines (what pandas does). Edit the text or pick a trap.

newline in quotesdoubled quotespace before quotebackslash escapeblank linebare quoteunterminated
split on commas3 rows · 3/4 fields
idnamecity
1 "Lee K"Leeds
2"Ng"York
RFC 4180 strict3 rows · 3/4 fields
idnamecity
1 "Lee K"Leeds
2NgYork
L2: bare quote inside an unquoted field · L2: bare quote inside an unquoted field
skip space after delimiter3 rows · 3 fields
idnamecity
1Lee, KLeeds
2NgYork
backslash escapes3 rows · 3/4 fields
idnamecity
1 "Lee K"Leeds
2NgYork
skip blank lines3 rows · 3/4 fields
idnamecity
1 "Lee K"Leeds
2NgYork
writer lab · on the loaded file

Write it back so anything can read it

Choose how fields are quoted, the delimiter, line endings and BOM. The output is parsed again with the strict reader and compared field by field. “Defuse formulas” prefixes cells that start with = + − @ (and tab or CR) with an apostrophe, which OWASP recommends against CSV injection.

quoting
only when neededall non-numericevery field
delimiter
commasemicolontab
line endings
CRLF (RFC)LF
byte order mark
no BOMUTF-8 BOM for Excel
formula cells
defuse with 'leave as is
round trip ✓ 9 records, every field identical (after defusing)download
order_id,sku,postcode,qty,date,customer,comment␍↵1001,MARCH1,02134,3,03/04/2026,"Smith, J",ok␍↵1002,1E5,90210,1,13/04/2026," ""Lee"," K""",spaces before the quote␍↵1003,SEPT2,00501,2,4-5,"Ana ""the boss"" Ruiz",bare quotes␍↵1004,AB-77,10115,5,2026-04-14,"O\Neil""",backslash escape␍↵␍↵1005,ZX-9,4111111111111111,1,2026-04-15,"'=HYPERLINK(""http://evil.example""",Click),formula␍↵1006,QQ-1,75001,2,2026-04-16,Müller,extra,fields,here␍↵1007,QQ-2,1000,1,2026-04-17,"unterminated,never closed1008,QQ-3,2000,1,2026-04-18,Late,row"␍↵

Reference

writer / readerdelimiterquote escapeline endnotes
RFC 4180,""CRLFthe reference; ASCII only, header optional
Excel (en-US),""CRLFreads with the system code page unless a BOM is present; honours sep= first line
Excel (de-DE, fr-FR…);""CRLFlist separator follows the locale because “,” is the decimal mark
Google Sheets,""LFUTF-8, no BOM on export
Python csv,""CRLFexcel dialect by default; skipinitialspace, escapechar, strict are options
PostgreSQL COPY CSV,""LFempty unquoted = NULL, quoted empty = empty string
MySQL LOAD DATATAB\"LFESCAPED BY '\\' by default; \N = NULL
TSV (IANA)TABnoneLFtabs simply may not appear in fields
RFC 4180 grammar, abridged
file = [header CRLF] record *(CRLF record) [CRLF]record = field *(COMMA field)field = escaped / non-escapedescaped = DQUOTE *(TEXTDATA / COMMA / CR / LF / 2DQUOTE) DQUOTEnon-escaped = *TEXTDATATEXTDATA = %x20-21 / %x23-2B / %x2D-7E
TEXTDATA is printable ASCII only: the RFC itself has no answer for “é”. Every real reader extends it to any non-delimiter character.
MIMEtext/csv (RFC 7111 adds #row=, #col=, #cell= fragments); parameters charset and header=present|absent
Extensions.csv; .tsv / .tab for tab-separated
Magic bytesnone: CSV is identified by extension or sniffing
Excel limits1,048,576 rows and 16,384 columns; longer files are cut off on open
Field sizeno limit in the RFC; Python’s default field_size_limit is 131,072 characters
CSV on the WebW3C 2015: a JSON metadata file describing columns, types and keys
Injectioncells starting with = + − @ tab or CR can run as formulas; prefix or quote them
1972IBM FortranList-directed input accepts comma-separated values.
1983the name“Comma-separated values” appears in software manuals for spreadsheets like SuperCalc.
1987Excel 2.0CSV becomes the default exchange format between spreadsheets and databases.
2005RFC 4180Yakov Shafranovich documents the common format and registers text/csv.
2014RFC 7111Fragment identifiers for rows, columns and cells.
2015CSVWW3C Recommendations for CSV metadata on the web.

Moving data in and out of CSV