转换时导出的csv文件中的奇怪字符

时间:2010-03-14 09:11:50

标签: python csv

我遇到了一个问题,我无法自行解决Google Insights for Search中可下载的csv格式趋势数据文件。

我懒得重新格式化文件I4S手动给我的意思是:用实际趋势数据提取部分并重新格式化列,以便我可以将它用于我为学校做的建模程序。

所以我写了一个小脚本应该为我做的工作:拿一个文件,做一些魔术并给我一个正确格式的新文件。

它应该做的是读取文件内容,提取趋势部分,按换行分割它们,拆分每一行然后重新排序列并重新格式化它们。

当查看未触及的I4S csv文件时,它看起来很正常,包含换行符时的CR LF字符(也许这只是因为我使用的是Windows)。

当只是阅读内容然后使用脚本将它们写入新文件时,CR和LF之间会出现奇怪的亚洲字符。我尝试使用手动编写的类似文件的脚本,甚至尝试了谷歌趋势的csv文件,它工作正常。

我使用Python和我用于以下示例的脚本(片段) 看起来像这样:

            # Read from an input file 
            file = open(file,"r") 
            contents = file.read() 
            file.close() 
            cfile = open("m.log","w+") 
            cfile.write(contents) 
            cfile.close()

有谁知道为什么这些字符出现???谢谢你的帮助!

我会给你和榜样:

I4S csv文件的前几行:

Web Search Interest: foobar
Worldwide; 2004 - present

Interest over time
Week foobar
2004-01-04 - 2004-01-10 44
2004-01-11 - 2004-01-17 44
2004-01-18 - 2004-01-24 37
2004-01-25 - 2004-01-31 40
2004-02-01 - 2004-02-07 49
2004-02-08 - 2004-02-14 51
2004-02-15 - 2004-02-21 45
2004-02-22 - 2004-02-28 61
2004-02-29 - 2004-03-06 51
2004-03-07 - 2004-03-13 48
2004-03-14 - 2004-03-20 50
2004-03-21 - 2004-03-27 56
2004-03-28 - 2004-04-03 59

读取和写入内容时的输出文件:

Web Search Interest: foobar
਍圀漀爀氀搀眀椀搀攀㬀 ㈀  㐀 ⴀ 瀀爀攀猀攀渀琀ഀഀ

਍䤀渀琀攀爀攀猀琀 漀瘀攀爀 琀椀洀攀ഀഀ
Week foobar
਍㈀  㐀ⴀ ㄀ⴀ 㐀 ⴀ ㈀  㐀ⴀ ㄀ⴀ㄀ ऀ㐀㐀ഀഀ
2004-01-11 - 2004-01-17 44
਍㈀  㐀ⴀ ㄀ⴀ㄀㠀 ⴀ ㈀  㐀ⴀ ㄀ⴀ㈀㐀ऀ㌀㜀ഀഀ
2004-01-25 - 2004-01-31 40
਍㈀  㐀ⴀ ㈀ⴀ ㄀ ⴀ ㈀  㐀ⴀ ㈀ⴀ 㜀ऀ㐀㤀ഀഀ
2004-02-08 - 2004-02-14 51
਍㈀  㐀ⴀ ㈀ⴀ㄀㔀 ⴀ ㈀  㐀ⴀ ㈀ⴀ㈀㄀ऀ㐀㔀ഀഀ
2004-02-22 - 2004-02-28 61
਍㈀  㐀ⴀ ㈀ⴀ㈀㤀 ⴀ ㈀  㐀ⴀ ㌀ⴀ 㘀ऀ㔀㄀ഀഀ
2004-03-07 - 2004-03-13 48
਍㈀  㐀ⴀ ㌀ⴀ㄀㐀 ⴀ ㈀  㐀ⴀ ㌀ⴀ㈀ ऀ㔀 ഀഀ
2004-03-21 - 2004-03-27 56
਍㈀  㐀ⴀ ㌀ⴀ㈀㠀 ⴀ ㈀  㐀ⴀ 㐀ⴀ ㌀ऀ㔀㤀ഀഀ
2004-04-04 - 2004-04-10 69
਍㈀  㐀ⴀ 㐀ⴀ㄀㄀ ⴀ ㈀  㐀ⴀ 㐀ⴀ㄀㜀ऀ㘀㔀ഀഀ
2004-04-18 - 2004-04-24 51
਍㈀  㐀ⴀ 㐀ⴀ㈀㔀 ⴀ ㈀  㐀ⴀ 㔀ⴀ ㄀ऀ㔀㄀ഀഀ
2004-05-02 - 2004-05-08 56
਍㈀  㐀ⴀ 㔀ⴀ 㤀 ⴀ ㈀  㐀ⴀ 㔀ⴀ㄀㔀ऀ㔀㈀ഀഀ
2004-05-16 - 2004-05-22 54
਍㈀  㐀ⴀ 㔀ⴀ㈀㌀ ⴀ ㈀  㐀ⴀ 㔀ⴀ㈀㤀ऀ㔀㔀ഀഀ
2004-05-30 - 2004-06-05 74
਍㈀  㐀ⴀ 㘀ⴀ 㘀 ⴀ ㈀  㐀ⴀ 㘀ⴀ㄀㈀ऀ㔀㜀ഀഀ
2004-06-13 - 2004-06-19 50
਍㈀  㐀ⴀ 㘀ⴀ㈀  ⴀ ㈀  㐀ⴀ 㘀ⴀ㈀㘀ऀ㔀㐀ഀഀ
2004-06-27 - 2004-07-03 58
਍㈀  㐀ⴀ 㜀ⴀ 㐀 ⴀ ㈀  㐀ⴀ 㜀ⴀ㄀ ऀ㔀㤀ഀഀ
2004-07-11 - 2004-07-17 59
਍㈀  㐀ⴀ 㜀ⴀ㄀㠀 ⴀ ㈀  㐀ⴀ 㜀ⴀ㈀㐀ऀ㘀㈀ഀഀ

3 个答案:

答案 0 :(得分:3)

repr()是您的朋友(Python 3.X除外;请改用ascii())。

prompt>\python26\python -c "print repr(open('report.csv','rb').read()[:300])"
'\xff\xfeW\x00e\x00b\x00 \x00S\x00e\x00a\x00r\x00c\x00h\x00 \x00I\x00n\x00t\x00e
\x00r\x00e\x00s\x00t\x00:\x00 \x00f\x00o\x00o\x00b\x00a\x00r\x00\r\x00\n\x00W\x0
[snip]
x001\x007\x00\t\x004\x004\x00\r\x00\n\x002\x000\x00'

对我来说,在前两个字节中看起来像UTF-16LE BOM(U + FEFF)。

记事本。*不是你的朋友。 UTF-16 应该被称为“UCS-2”或“Unicode”。

以下内容应该有助于下一步做什么:

>>> import codecs
>>> lines = list(codecs.open('report.csv', 'r', encoding='UTF-16'))
>>> import pprint
>>> pprint.pprint(lines[:8])
[u'Web Search Interest: foobar\r\n',
 u'Worldwide; 2004 - present\r\n',
 u'\r\n',
 u'Interest over time\r\n',
 u'Week\tfoobar\r\n',
 u'2004-01-04 - 2004-01-10\t44\r\n',
 u'2004-01-11 - 2004-01-17\t44\r\n',
 u'2004-01-18 - 2004-01-24\t37\r\n']
>>>

更新:为什么输出文件看起来像gobbledegook。

首先,您正在查看带有某些内容的文件(Notepad。* may),这些文件知道这些文件是以UTF-16LE编码的,并相应地显示它们。所以你的输入文件看起来很好。

但是,您的脚本正在将输入文件作为原始字节读取。然后它以文本模式('w')将输出文件写为原始字节(而不是二进制模式('wb'))。由于您使用的是Windows,因此每个\n都会被\r\n替换。这是为每一行添加一个字节(UTF-16字符的HALF)。因此,每条SECOND线都将是低音大战,也就是UTF-16BE ...... UTF-16LE中的字母A是\ x41 \ x00将丢失其尾随的\ x00并从左边的字符中拾取一个前导字节(可能是\ x00) 。 \ x00 \ x41是CJK(“亚洲”)角色的UTF-16LE。

建议阅读:Python Unicode HOWTOthis piece by Joel

答案 1 :(得分:3)

问题是字符编码,可能与Python的通用行结束支持相结合。如前所述,源文件位于UCS-2 LE中,带有字节顺序标记(BOM)。您需要执行以下操作:

import codecs

input_file = codecs.open("Downloads/report.csv", "r", encoding="utf_16")
contents = input_file.read() 
input_file.close() 

cfile = codecs.open("m.log", "w+", encoding="utf_8")
cfile.write(contents) 
cfile.close()

这将读取输入文件,正确解码,并将其作为UTF-8写入新文件。您需要删除现有的m.log。

答案 2 :(得分:2)

找到解决方案:

这是一个字符编码问题。根据您使用的编辑器,显示其他字符集编码:

Notepad ++:ucs-2 little endian PSPad:utf-16le

使用ucs-2解码内容不起作用所以我尝试了utf-16le并且进展顺利。 extraneons回答是错误的,但是它引导我到了我知道在文件打开方法中使用'U'导致识别“\ r \ n”作为换行符的网站。所以现在我的脚本的相关片段如下所示:

file = open(file,'rU')
contents = file.read()
file.close()

contents = contents.decode("utf-16le").encode("utf-8")

然后我用utf-8编码内容并用

删除所有空行
lines = contents.split("\n")
contents = ""
for line in lines:
  if not line.strip():
    continue
  else:
    contents += line+"\n"

现在我可以继续拆分并重新格式化文件了。感谢Nick Bastin,你给了我需要的提示!