在 python 中正确读取 Windows-1252(cp1252) 文件中的文本
Posted
技术标签:
【中文标题】在 python 中正确读取 Windows-1252(cp1252) 文件中的文本【英文标题】:Correctly reading text from Windows-1252(cp1252) file in python 【发布时间】:2013-03-08 07:29:25 【问题描述】:好吧,正如标题所示,我遇到的问题是从 python 中的 windows-1252 编码文件中正确读取输入并将所述输入插入 SQLAlchemy-mysql 表中。
当前系统设置: 带有输出文件的“Roger 访问控制系统”的 Windows 7 VM; Ubuntu 12.04 LTS VM 与 Windows 系统的共享文件夹,因此我可以使用“Python 2.7.3”访问该文件。
现在到实际问题,对于输入文件,我有一个“VM 共享文件夹”,其中包含一个通过 Roger 访问控制系统在 Windows 7 系统上生成的文件(更多详细信息,roger.pl),这个文件被称为“PREvents.csv”,这表明它的内容是“;”单独的数据列表。
数据格式示例:
2013-03-19;15:58:30;100;Jānis;Dumburs;1;Uznemums1;0;Ieeja;
2013-03-19;15:58:40;100;Jānis;Dumburs;1;Uznemums1;2;Izeja;
第 4 个字段包含卡所有者姓名,第 5 个字段包含所有者姓氏,第 6 个字段包含所有者分配的组。
问题在于上述 3 个字段中的任何一个都可以包含特定于拉脱维亚语言的字符,在示例文件中,单词“Jānis”包含字母“ā”,在 unicode 中是 257。
按照我的习惯,我这样打开文件:
try:
f = codecs.open(file, 'rb', 'cp1252')
except IOError:
f = codecs.open(file, 'wb', 'cp1252')
到目前为止,一切正常 - 它打开了文件,所以我继续迭代文件的每一行(这是一个连续运行的脚本,所以请原谅循环):
while True:
line = f.readline()
if not line:
# Pause loop for 1 second
time.sleep(1)
else:
# Split the line into list
date, timed, userid, firstname, lastname, groupid, groupname, typed, pointname, empty = line.split(';')
这就是问题的开始,如果我 print repr(firstname)
它打印 u'J\xe2nis'
,据我所知,这是不正确的 - `\xe2\ 不代表拉脱维亚字符“ā”。
根据事件类型,在循环的下方,我将变量分配给 SQLAlchemy 对象并插入/更新:
if typed == '0': # Entry type
event = Events(
period,
fullname,
userid,
groupname,
timestamp,
0,
0
)
session.add(event)
else: # Exit type
event = session.query(Events).filter(
Events.period == period,
Events.exit == 0,
Events.userid == userid
).first()
if event is not None:
event.exit = timestamp
event.spent = timestamp - event.entry
# Commit changes to database
session.commit()
在我寻找答案的过程中,我发现了如何定义要使用的默认编码:
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
这对我没有任何帮助。
基本上,这一切都会导致我无法插入正确的所有者名字/姓氏以及所有者分配的组名,如果它们包含任何拉脱维亚特定字符,例如:
Instead of the character "ā" it inserts "â"
我还想补充一点,我无法更改“PREvents.csv”文件编码,并且“RACS”系统不支持插入 UTF-8 或 Unicode 文件 - 如果您尝试任何一种方式,系统都会随机插入拉脱维亚特定字符的符号。
如果需要任何其他信息,请现在告诉我,我很乐意提供:)
任何帮助将不胜感激。
【问题讨论】:
拉脱维亚字符 ā 在 CP1252 中根本不可用。您不能创建包含该字符的 CP1252 编码文件。 (你有一个用 CP1257 编码的文件吗?) 当执行sudo file /media/sf_attendance/PREvents.csv
我得到/media/sf_attendance/PREvents.csv: ISO-8859 text, with CRLF line terminators
ISO-8859 是一个编码系列; CP1252 类似于(但不等同于)ISO-8859-1,仅支持西欧语言; CP1257 支持波罗的海语言。
【参考方案1】:
CP1252 不能代表ā;您的输入包含相似的字符 â。 repr
仅在 Python 2.x 中显示 Unicode 字符串的 ASCII 表示:
>>> print(repr(b'J\xe2nis'.decode('cp1252')))
u'J\xe2nis'
>>> print(b'J\xe2nis'.decode('cp1252'))
Jânis
【讨论】:
好的,所以将文件打开行更改为f = codecs.open(file, 'rb', 'cp1257')
,然后将print firstname
显示正确的“ā”,但现在在执行session.commit()
时我得到UnicodeEncodeError: 'latin-1' codec can't encode character u'\u0101' in position 1: ordinal not in range(256)
您可能需要将 utf-8 设置为数据库(会话)的默认编码?
是的,我现在已经解决了这个问题 - 在 engine = create_engine(connection, convert_unicode=True)
中创建“引擎”时需要添加 convert_unicode=True
【参考方案2】:
我认为u'J\xe2nis'
是正确的,请参阅:
>>> print u'J\xe2nis'.encode('utf-8')
Jânis
您是否从 SQLAlchemy 或应用程序的输出中收到实际错误?
【讨论】:
如果我尝试firstname = firstname.decode('cp1252')
然后将其插入数据库,我仍然会得到字符“â”【参考方案3】:
我在处理一些 XML 文件时遇到了同样的问题,我解决了使用 ANSI 编码 (Windows-1252) 读取文件并使用 UTF-8 编码写入文件:
import os
import sys
path = os.path.dirname(__file__)
file_name = 'my_input_file.xml'
if __name__ == "__main__":
with open(os.path.join(path, './' + file_name), 'r', encoding='cp1252') as f1:
lines = f1.read()
f2 = open(os.path.join(path, './' + 'my_output_file.xml'), 'w', encoding='utf-8')
f2.write(lines)
f2.close()
【讨论】:
以上是关于在 python 中正确读取 Windows-1252(cp1252) 文件中的文本的主要内容,如果未能解决你的问题,请参考以下文章