16

I am trying to create a csv file using python that is truly Excel-compatible (I am using Excel 2007, if that makes any difference).

Here is the sort of thing I'm trying to do

import csv

data = [ ['9-1', '9-2', '9-3'] ]

fd = open('test.csv', 'wb')
try:
    writer = csv.writer(fd, dialect='excel', quotechar='"', quoting=csv.QUOTE_ALL)
    writer.writerows(data)

finally:
    fd.close()

This creates a csv file that contains:

"9-1","9-2","9-3"

When I load it in Excel, I get the columns:

09-Jan  09-Feb  09-Mar

[Grrr, thanks Excel. Seriously, what is the point of quotes?]

Now, I have read elsewhere that in order to get Excel to treat strings as literal they must be prefixed by an equals sign ="Like This". So what I really want to produce is:

="9-1",="9-2",="9-3"

Is there any way to do this with the csv module in python? I'm guessing it will involve creating a custom dialect, but I can't see any variable that would give me the desired result.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Lee Netherton
  • 21,347
  • 12
  • 68
  • 102

6 Answers6

8

If your aim is just writing a list as a table on Excel. You can try below sample, where ";" and dialect='excel-tab' property enables us to switch between coloumns.

import csv

RESULTS = [
    ['val_col1;','val_col2;','val_col3']
]
resultFile = open("testExcel.csv",'wb')
resultWriter= csv.writer(resultFile, dialect='excel-tab')
resultWriter.writerows(RESULTS)
kara
  • 81
  • 1
  • 3
6

FWIW, Excel 2007 is not even compatible with itself. If you type 9-1 into an empty spreadsheet, it converts it to 1-Sep as soon as you leave the cell. If you change the cell format from General to Text, you can enter the string literals unchanged and save it as a .csv file, but when you read the same file into a blank spreadsheet (with General format) it gets reconverted to dates.

Excel saves the file as

9-1,9-2,9-3

without quotes and without "=" signs. Even setting the cell formats to Text before reading the csv file doesn't work for me - it imports as dates (display value 1-Sep, cell value 9/1/2011) with the 3 cells in Custom format; the rest of the cells are converted to General.

Edit: A csv file containing:

"9-1",'9-2',='9-3',=''9-4''

reads into the spreadsheet as:

1-Sep  '9-2'  ='9-3'  ="9-4"

So the = doesn't do any good, but at least the single quotes will get a string literal, with the quotes preserved. Someone more knowlegeable in Excel will have to help with getting rid of the quotes; "paste values" doesn't strip them off.

Dave
  • 3,834
  • 2
  • 29
  • 44
  • 2
    Yep, Excel sucks. I wouldn't even be using it except that some people in my workplace insist on using it to view data. – Lee Netherton Nov 14 '11 at 16:54
5

The problem is that you're importing your CSV file into Excel using Excel's CSV importer. Counterintuitive, I know, but you should not import CSV files that way. Instead, import them as text files (i.e., name with a txt extension). Then you will have the opportunity to specify the type of each column and can properly choose Text for columns that look like dates to Excel.

If you're looking for a turnkey "here is a file you can open in Excel" approach, try xlwt (not my original recommendation pyXLWriter) and avoid CSV entirely.

smci
  • 32,567
  • 20
  • 113
  • 146
kindall
  • 178,883
  • 35
  • 278
  • 309
  • 1
    Thanks. I changed the file extension to .txt which forced Excel to bring up the text importer wizard. However, I have to select each column individually and choose to import as Text (there is no way to select more than one column). With 100s of columns, this is not really a usable solution for me :-( – Lee Netherton Nov 14 '11 at 16:52
  • 1
    You *can* choose multiple columns and change them all at once with Shift-Click in Step 3. – kindall Nov 14 '11 at 17:09
  • Oh yeah. It's working now... I guess I must have tried Ctrl and not Shift. Thanks – Lee Netherton Nov 14 '11 at 17:23
  • 2
    You could also consider xlwt as another way to write excel files directly from python which is available at http://www.python-excel.org/ It has worked quite well for me on a couple of projects. – TimothyAWiseman Nov 14 '11 at 17:52
  • -1 for pyXLWriter. That is as one with the Norwegian Blue Parrot. Even though sourceforge shows 12 downloads this week. Did you cause that?? It is not maintained (last update: 6 years ago), writes Excel 5/7 XLS files, and is buggy. – John Machin Nov 14 '11 at 20:40
  • Hundreds of columns? How many hundreds? If it's more that 256 columns, you'll need something like pyopenxl; otherwise use xlwt. – John Machin Nov 14 '11 at 20:42
  • Found pyXLWriter recommended on a forum as being easy to use. It had 12 downloads when I found it too, so none of those downloads were a result of this. Writing an old format of Excel wouldn't be a problem for this application. – kindall Nov 14 '11 at 21:12
  • ... as for the bugs, I'll defer to you on that, and have edited to recommend xlwt. – kindall Nov 14 '11 at 21:39
2

Ok, thanks for all your help, I've come up with a rough solution, so I thought I'd share it here.

It's not the prettiest of solutions but it works for my purposes. A warning though: It will break if you have any quotes in your strings!

import csv
import re

data = [ ['9-1', '9-2', '9-3'] ]


def quoteCsvData(data):
    for x, row in enumerate(data):
        for y, item in enumerate(row):
             if data[x][y] != '':
                 data[x][y] = r'="' + data[x][y] + r'"'
    return data

def unquoteCsvData(data):
    for x, row in enumerate(data):
        for y, item in enumerate(row):
            if data[x][y] != '':
                m = re.match(r'="([^"]*)"',data[x][y])
                if m:
                    data[x][y] =  m.group(1)
    return data


fd = open('test2.csv', 'wb')
data = quoteCsvData(data)
try:
    writer = csv.writer(fd, delimiter=',',
                            quotechar='|', 
                            quoting=csv.QUOTE_NONE, 
                            escapechar='\\')
    writer.writerows(data)

finally:
    fd.close()

fd = open('test2.csv', 'rb')
try:
    reader = csv.reader(fd, delimiter=',', 
                            quotechar='|', 
                            quoting=csv.QUOTE_NONE, 
                            escapechar='\\')
    data = []
    for row in reader:
        data.append(row)

finally:
    fd.close()

data = unquoteCsvData(data)

print data

Update: removed spamming of empty cells with lots of =""

Lee Netherton
  • 21,347
  • 12
  • 68
  • 102
-3

try::

dialect=csv.excel

as in

import csv
csv.excel 
  • lineterminator '\r\n'
  • skipinitialspace False
  • quoting 0
  • delimiter ','
  • quotechar '"'
  • doublequote True

For me its a bit of a black art that has never bothered me enough to go read the code, but the little experimentation I did always got excel (2003) to behave well enough with the above formats.

Community
  • 1
  • 1
lifeisstillgood
  • 3,265
  • 2
  • 21
  • 22
-3
data = [ ['9-1', '9-2', '9-3'] ]
fd = open('test.csv', 'wb')
for row in data:
    for x in row:
        fd.write('="{}",'.format(x))
    fd.write('\n')
totowtwo
  • 2,101
  • 1
  • 14
  • 21
  • 2
    The problem isn't getting Python to write a file, it's getting Excel to read a .csv file without mangling the data. – Dave Nov 14 '11 at 17:00