You can give your writer instance a custom lineterminator argument in the constructor:

writer = csv.writer(f, lineterminator="\n")
Answer from Niklas B. on Stack Overflow
🌐
Python
docs.python.org › 3 › library › csv.html
csv — CSV File Reading and Writing
... The string used to terminate lines produced by the writer. It defaults to '\r\n'. ... The reader is hard-coded to recognise either '\r' or '\n' as end-of-line, and ignores lineterminator.
🌐
Reddit
reddit.com › r/learnpython › csv writer: append doesn't go to new line
r/learnpython on Reddit: csv writer: append doesn't go to new line
January 26, 2021 -

So, basically, I've got this code:

new_list_csv = []

def add_it():
    #gets the values from Entry
    #three different tk Entrys generate three different values
    name= self.e.get()
    ex= self.e_x.get()
    ey= self.e_y.get()
    #adds them to the new list
    new_list_csv.append(name)
    new_list_csv.append(ex)
    new_list_csv.append(ey)
    #appends new characters to csv file
    with open ('chr_list_copy.txt', 'a', newline='') as write_obj:   
        csv_writer = csv.writer(write_obj)
        csv_writer.writerow(new_list_csv)

and the csv file looks like this:

name,x,y
Ergo,1,1
Sum,5,5
Name12,1,2
Name34,3,4
Name56,5,6
Name78,7,8
Name910,9,10
Name1112,11,12
Name1314,13,14

if I try and add [Otto,6,9], I get:

name,x,y
[...]
Name1314,13,14Otto,6,9

instead of:

name,x,y
[...]
Name1314,13,14
Otto,6,9

I've used this very same structure for the rest of my code, but in this specific instance, it doesn't work.

Top answer
1 of 6
540

Python 3:

The official csv documentation recommends opening the file with newline='' on all platforms to disable universal newlines translation:

with open('output.csv', 'w', newline='', encoding='utf-8') as f:
    writer = csv.writer(f)
    ...

The CSV writer terminates each line with the lineterminator of the dialect, which is '\r\n' for the default excel dialect on all platforms because that's what RFC 4180 recommends.


Python 2:

On Windows, always open your files in binary mode ("rb" or "wb"), before passing them to csv.reader or csv.writer.

Although the file is a text file, CSV is regarded a binary format by the libraries involved, with \r\n separating records. If that separator is written in text mode, the Python runtime replaces the \n with \r\n, hence the \r\r\n observed in the file.

See this previous answer.

2 of 6
291

While @john-machin gives a good answer, it's not always the best approach. For example, it doesn't work on Python 3 unless you encode all of your inputs to the CSV writer. Also, it doesn't address the issue if the script wants to use sys.stdout as the stream.

I suggest instead setting the 'lineterminator' attribute when creating the writer:

import csv
import sys

doc = csv.writer(sys.stdout, lineterminator='\n')
doc.writerow('abc')
doc.writerow(range(3))

That example will work on Python 2 and Python 3 and won't produce the unwanted newline characters. Note, however, that it may produce undesirable newlines (omitting the LF character on Unix operating systems).

In most cases, however, I believe that behavior is preferable and more natural than treating all CSV as a binary format. I provide this answer as an alternative for your consideration.

🌐
Reddit
reddit.com › r/learnpython › how to remove '\r\n' from the csv records being written?
r/learnpython on Reddit: How to remove '\r\n' from the csv records being written?
July 30, 2015 -

I am running the script on a Windows 7 machine using Python 3.4.1. The script runs correctly and produces a csv file, the only problem is at the end of each line is a '\r\n' which causes an extra blank line to appear when displayed in Excel. How do get remove the extra blank line?

import pyodbc
import csv

connect = pyodbc.connect('driver={SQL Server Native       Client 10.0};SERVER=xxxxx-7-   VM;DATABASE=DEMO_xxxx_TEST;UID=DEMO_xxxx_TEST;PWD=password')

cursor = connect.cursor()

cursor.execute('''select Report_name
                    ,UserID
                    ,FieldName
                    ,XPos
                    ,YPos
                    ,Hidden
                    ,Picture
              from  Rpt_Nudge_2
              where Report_Name = 'UB04' and UserID = 'myid' and YPos > 8886 and YPos < 9888
              order by YPos, XPos''')

col_names = [i[0] for i in cursor.description]
print(col_names)

nudge = cursor.fetchall()

with open('UB04_nudge.csv', 'w') as csvfile:
    fileout = csv.writer(csvfile)
    row = fileout.writerow(col_names)
    for line in nudge:
        fileout.writerow(line)

connect.close()
🌐
Python Morsels
pythonmorsels.com › csv-writing
Writing a CSV file - Python Morsels
February 14, 2023 - Python's csv writer ends each of its lines with a carriage return followed by a line feed (i.e.
🌐
Reddit
reddit.com › r/excel › rookie question about csv files. what changes if there is a comma at the very end of a line? would that just translate into an empty cell?
r/excel on Reddit: Rookie question about CSV files. What changes if there is a comma at the very end of a line? Would that just translate into an empty cell?
December 20, 2020 -

I was trying to create a script (python) that generates CSV files but couldn’t get it to work so I lazy mcguyver’d a text file with a comma separating the values, then changing the extension from .txt to .csv.

So think:

First Name,Last Name,
Tom,Jerry,
Mike,Holmes,

My question is: is there any performance lost or extra space created by the trailing comma? I’m asking so I know weather or not to invest more time in actually properly generating a csv file or even a xls file down the road.

Find elsewhere
🌐
GitHub
github.com › JoshClose › CsvHelper › issues › 1775
CsvWriter.WriteHeader<>() don't write newline causing -WriteRecords() to start on header -line · Issue #1775 · JoshClose/CsvHelper
April 19, 2021 - This writes the header fine, but doesn't end with a "newline", which causes "WriteRecords" to begin writing on the end of the header line. ... public void Write<T, TMap>(FileInfo file, List<T> records) where TMap : ClassMap<T> where T : class, new() { using var fileStream = new MemoryStream(); using var writer = new StreamWriter(fileStream); using var csv = new CsvWriter(writer, CsvConfiguration); csv.Context.RegisterClassMap<TMap>(); csv.WriteHeader<T>(); csv.WriteRecords(records); csv.Flush(); File.WriteAllBytes(file.FullName, fileStream.ToArray()); }
Author   JoshClose
🌐
Python
docs.python.org › 3.2 › library › csv.html
13.1. csv — CSV File Reading and Writing — Python v3.2.6 documentation
October 12, 2014 - The string used to terminate lines produced by the writer. It defaults to '\r\n'. ... The reader is hard-coded to recognise either '\r' or '\n' as end-of-line, and ignores lineterminator.
🌐
Python
bugs.python.org › issue7198
Issue 7198: Extraneous newlines with csv.writer on Windows - Python tracker
This issue tracker has been migrated to GitHub, and is currently read-only. For more information, see the GitHub FAQs in the Python's Developer Guide · This issue has been migrated to GitHub: https://github.com/python/cpython/issues/51447
Top answer
1 of 2
19

Here is a simple solution: Replace all \n with \\n before saving to CSV. This will preserve the newline characters.

df.loc[:, "Column_Name"] = df["Column_Name"].apply(lambda x: x.replace('\n', '\\n'))
df.to_csv("df.csv", index=False)
2 of 2
10

I assume that you want to keep the newlines in the strings for some reason after you have loaded the csv files from disk. Also that this is done again in Python. My solution will require Python 3, although the principle could be applied to Python 2.

The main trick

This is to replace the \n characters before writing with a weird character that otherwise wouldn't be included, then to swap that weird character back for \n after reading the file back from disk.

For my weird character, I will use the Icelandic thorn: Þ, but you can choose anything that should otherwise not appear in your text variables. Its name, as defined in the standardised Unicode specification is: LATIN SMALL LETTER THORN. You can use it in Python 3 a couple of ways:

    weird_literal = 'þ'
    weird_name = '\N{LATIN SMALL LETTER THORN}'
    weird_char = '\xfe'  # hex representation
    weird_literal == weird_name == weird_char  # True

That \N is pretty cool (and works in python 3.6 inside formatted strings too)... it basically allows you to pass the Name of a character, as per Unicode's specification.

An alternative character that may serve as a good standard is '\u2063' (INVISIBLE SEPARATOR).

Replacing \n

Now we use this weird character to replace '\n'. Here are the two ways that pop into my mind for achieving this:

  1. using a list comprehension on your list of lists: data:

     new_data = [[sample[0].replace('\n', weird_char) + weird_char, sample[1]]
                  for sample in data]
    
  2. putting the data into a dataframe, and using replace on the whole text column in one go

     df1 = pd.DataFrame(data, columns=['text', 'category'])
     df1.text = df.text.str.replace('\n', weird_char)
    

The resulting dataframe looks like this, with newlines replaced:

               text              category
0         some text in one line      1   
1  text withþnew line character      0   
2    another newþline character      1   

Writing the results to disk

Now we write either of those identical dataframes to disk. I set index=False as you said you don't want row numbers to be in the CSV:

FILE = '~/path/to/test_file.csv'
df.to_csv(FILE, index=False)

What does it look like on disk?

text,category

some text in one line,1

text withþnew line character,0

another newþline character,1

Getting the original data back from disk

Read the data back from file:

new_df = pd.read_csv(FILE)

And we can replace the Þ characters back to \n:

new_df.text = new_df.text.str.replace(weird_char, '\n')

And the final DataFrame:

new_df
               text               category
0          some text in one line      1   
1  text with\nnew line character      0   
2    another new\nline character      1   

If you want things back into your list of lists, then you can do this:

original_lists = [[text, category] for index, text, category in old_df_again.itertuples()]

Which looks like this:

[['some text in one line', 1],
 ['text with\nnew line character', 0],
 ['another new\nline character', 1]]
🌐
GitHub
github.com › tidyverse › readr › issues › 857
write_csv should have an option to specify end of line character · Issue #857 · tidyverse/readr
May 23, 2018 - There should be an option to specify what character should be on the end of a line. I am dealing with a process of loading data to a database from .csv files, and it only works when the eol is a Carriage Return Line Feed (as is done when Windows Excel saves a .csv file).
Author   tidyverse
🌐
SourceForge
opencsv.sourceforge.net › apidocs › com › opencsv › CSVWriter.html
CSVWriter (opencsv 5.12.0 API)
Constructs CSVWriter with supplied separator, quote char, escape char and line ending. ... protected void writeNext(String[] nextLine, boolean applyQuotesToAll, Appendable appendable) throws IOException ... Writes the next line to the file. This method is a fail-fast method that will throw the IOException of the writer supplied to the CSVWriter (if the Writer does not handle the exceptions itself like the PrintWriter class).
🌐
KnowledgeHut
knowledgehut.com › https://www.knowledgehut.com › tutorials › programming tutorials
Python CSV Tutorial: Read, Write & Manipulate CSV Files in Python
Since reader object is an iterator stream, built-in next() function is also useful to display all lines in csv file. >>> csvfile=open(marks.csv','r', newline='') >>> obj=csv.reader(csvfile) >>> while True: try: row=next(obj) print (row) except StopIteration: break · This function creates a DictWriter object which is like a regular writer but maps dictionaries onto output rows. The function takes fieldnames parameter which is a sequence of keys.