Tôi thực sự khuyên bạn nên mã lại (các) tệp của mình thành UTF-8. Trong điều kiện rất có thể là bạn không có bất kỳ ký tự Unicode nào bên ngoài BMP, bạn có thể tận dụng thực tế là UTF-16 là mã hóa có độ dài cố định để đọc các khối có độ dài cố định từ tệp đầu vào của bạn mà không phải lo lắng về khối ranh giới.
Bước 1: Xác định loại mã hóa bạn thực sự có.Kiểm tra vài byte đầu tiên của tập tin của bạn:
print repr(open('thefile.csv', 'rb').read(100))
Bốn cách có thể mã hóa u'abc'
\xfe\xff\x00a\x00b\x00c -> utf_16
\xff\xfea\x00b\x00c\x00 -> utf_16
\x00a\x00b\x00c -> utf_16_be
a\x00b\x00c\x00 -> utf_16_le
Nếu bạn có bất kỳ rắc rối với bước này, chỉnh sửa câu hỏi của bạn để bao gồm các kết quả của các bên trên print repr()
Bước 2: Dưới đây là một Python 2.x recode-UTF-16 * -to-UTF-8 kịch bản:
import sys
infname, outfname, enc = sys.argv[1:4]
fi = open(infname, 'rb')
fo = open(outfname, 'wb')
BUFSIZ = 64 * 1024 * 1024
first = True
while 1:
buf = fi.read(BUFSIZ)
if not buf: break
if first and enc == 'utf_16':
bom = buf[:2]
buf = buf[2:]
enc = {'\xfe\xff': 'utf_16_be', '\xff\xfe': 'utf_16_le'}[bom]
# KeyError means file doesn't start with a valid BOM
first = False
fo.write(buf.decode(enc).encode('utf8'))
fi.close()
fo.close()
Các vấn đề khác:
Bạn nói rằng các file của bạn quá lớn để đọc các tập tin toàn bộ, recode và viết lại, nhưng bạn có thể mở nó trong vi
. Vui lòng giải thích.
Các < 85> được coi là kết thúc kỷ lục là một chút lo lắng. Có vẻ như 0x85
đang được nhận dạng là NEL (mã kiểm soát C1, NEWLINE). Có khả năng mạnh mẽ rằng dữ liệu ban đầu được mã hóa trong một số mã hóa byte đơn kế thừa, trong đó 0x85 có ý nghĩa nhưng đã được chuyển mã sang UTF-16 theo giả định sai rằng mã hóa ban đầu là ISO-8859-1 aka latin1. Tệp đã bắt nguồn từ đâu? Một máy tính lớn của IBM? Windows/Unix/Mac cổ điển? Quốc gia, ngôn ngữ, ngôn ngữ nào? Bạn rõ ràng nghĩ rằng < 85> không có nghĩa là một dòng mới; bạn nghĩ điều đó nghĩa là gì?
Xin vui lòng gửi một bản sao của một tập tin cắt xuống (trong đó bao gồm một số các < 85> công cụ) để sjmachin at lexicon dot net
Cập nhật dựa trên dữ liệu mẫu 1-line cung cấp.
Điều này xác nhận sự nghi ngờ của tôi. Đọc this. Dưới đây là một trích dẫn từ nó:
... the C1 control characters ... are rarely used directly, except on specific platforms such as OpenVMS. When they turn up in documents, Web pages, e-mail messages, etc., which are ostensibly in an ISO-8859-n encoding, their code positions generally refer instead to the characters at that position in a proprietary, system-specific encoding such as Windows-1252 or the Apple Macintosh ("MacRoman") character set that use the codes provided for representation of the C1 set with a single 8-bit byte to instead provide additional graphic characters
Mã này:
s1 = '\xff\xfe1\x00,\x002\x00,\x00G\x00,\x00S\x00,\x00H\x00 \x00f\x00\xfc\x00r\x00 \x00e\x00 \x00\x96\x00 \x00m\x00 \x00\x85\x00,\x00,\x00I\x00\r\x00\n\x00'
s2 = s1.decode('utf16')
print 's2 repr:', repr(s2)
from unicodedata import name
from collections import Counter
non_ascii = Counter(c for c in s2 if c >= u'\x80')
print 'non_ascii:', non_ascii
for c in non_ascii:
print "from: U+%04X %s" % (ord(c), name(c, "<no name>"))
c2 = c.encode('latin1').decode('cp1252')
print "to: U+%04X %s" % (ord(c2), name(c2, "<no name>"))
s3 = u''.join(
c.encode('latin1').decode('1252') if u'\x80' <= c < u'\xA0' else c
for c in s2
)
print 's3 repr:', repr(s3)
print 's3:', s3
sản xuất như sau (Python 2.7.2 IDLE, Windows 7):
s2 repr: u'1,2,G,S,H f\xfcr e \x96 m \x85,,I\r\n'
non_ascii: Counter({u'\x85': 1, u'\xfc': 1, u'\x96': 1})
from: U+0085 <no name>
to: U+2026 HORIZONTAL ELLIPSIS
from: U+00FC LATIN SMALL LETTER U WITH DIAERESIS
to: U+00FC LATIN SMALL LETTER U WITH DIAERESIS
from: U+0096 <no name>
to: U+2013 EN DASH
s3 repr: u'1,2,G,S,H f\xfcr e \u2013 m \u2026,,I\r\n'
s3: 1,2,G,S,H für e – m …,,I
Mà bạn có nghĩ là một giải thích hợp lý hơn về \x96
:
SPA tức là Bắt đầu khu vực được bảo vệ (Được sử dụng bởi block-ori thiết bị đầu cuối được giao.)
hoặc
EN DASH
?
Dường như việc phân tích kỹ lưỡng mẫu dữ liệu lớn hơn nhiều được bảo đảm. Vui vẻ giúp đỡ.
Cảm ơn @phihag vì phản hồi của bạn. Có cách nào để làm điều này mà không cần tải tập tin vào bộ nhớ? Tệp csv của tôi rất lớn. – venky
@venky Được cập nhật bằng một bản hack sẽ hoạt động trong phiên bản 2.x. – phihag
Tôi làm cách nào để biết tệp có bắt đầu bằng BOM khô[email protected] – venky