Tôi đã nhận được một số văn bản được mã hóa, nhưng tôi không biết bộ ký tự nào đã được sử dụng. Có cách nào để xác định mã hóa tệp văn bản bằng Python không? Làm cách nào tôi có thể phát hiện mã hóa / bảng mã của tệp văn bản giao dịch với C #.
Tôi đã nhận được một số văn bản được mã hóa, nhưng tôi không biết bộ ký tự nào đã được sử dụng. Có cách nào để xác định mã hóa tệp văn bản bằng Python không? Làm cách nào tôi có thể phát hiện mã hóa / bảng mã của tệp văn bản giao dịch với C #.
Câu trả lời:
Phát hiện chính xác mã hóa mọi lúc là không thể .
(Từ Câu hỏi thường gặp về chardet :)
Tuy nhiên, một số mã hóa được tối ưu hóa cho các ngôn ngữ cụ thể và ngôn ngữ không phải là ngẫu nhiên. Một số chuỗi nhân vật bật lên mọi lúc, trong khi các chuỗi khác không có ý nghĩa. Một người thông thạo tiếng Anh, người mở một tờ báo và tìm thấy TxzqJv 2! Bằng cách nghiên cứu nhiều văn bản điển hình của người Viking, một thuật toán máy tính có thể mô phỏng loại lưu loát này và đưa ra phỏng đoán có giáo dục về ngôn ngữ của văn bản.
Có thư viện chardet sử dụng nghiên cứu đó để cố gắng phát hiện mã hóa. chardet là một cổng của mã phát hiện tự động trong Mozilla.
Bạn cũng có thể sử dụng UnicodeDammit . Nó sẽ thử các phương pháp sau:
Một tùy chọn khác để thực hiện mã hóa là sử dụng libmagic (là mã đằng sau lệnh tệp ). Có một sự ràng buộc của ràng buộc trăn có sẵn.
Các ràng buộc python sống trong cây nguồn tệp có sẵn dưới dạng gói debian python-magic (hoặc python3-magic ). Nó có thể xác định mã hóa của một tệp bằng cách thực hiện:
import magic
blob = open('unknown-file', 'rb').read()
m = magic.open(magic.MAGIC_MIME_ENCODING)
m.load()
encoding = m.buffer(blob) # "utf-8" "us-ascii" etc
Có một gói pip python-Magic giống hệt nhau, nhưng không tương thích trên pypi cũng sử dụng libmagic
. Nó cũng có thể nhận được mã hóa, bằng cách thực hiện:
import magic
blob = open('unknown-file', 'rb').read()
m = magic.Magic(mime_encoding=True)
encoding = m.from_buffer(blob)
libmagic
thực sự là một lựa chọn khả thi để chardet
. Và thông tin tuyệt vời về các gói khác nhau được đặt tên python-magic
! Tôi chắc rằng sự mơ hồ này đã cắn nhiều người
file
không đặc biệt tốt trong việc xác định ngôn ngữ của con người trong các tệp văn bản. Thật tuyệt vời khi xác định các định dạng chứa khác nhau, mặc dù đôi khi bạn phải biết ý nghĩa của nó ("tài liệu Microsoft Office" có thể có nghĩa là một thông báo Outlook, v.v.).
open()
: UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfc in position 169799: invalid start byte
. Mã hóa tập tin theo vim :set fileencoding
là latin1
.
errors='ignore'
, đầu ra của mã ví dụ sẽ ít hữu ích hơn binary
.
Một số chiến lược mã hóa, xin vui lòng bỏ ghi chú:
#!/bin/bash
#
tmpfile=$1
echo '-- info about file file ........'
file -i $tmpfile
enca -g $tmpfile
echo 'recoding ........'
#iconv -f iso-8859-2 -t utf-8 back_test.xml > $tmpfile
#enca -x utf-8 $tmpfile
#enca -g $tmpfile
recode CP1250..UTF-8 $tmpfile
Bạn có thể muốn kiểm tra mã hóa bằng cách mở và đọc tệp dưới dạng vòng lặp ... nhưng trước tiên bạn có thể cần kiểm tra kích thước tệp:
encodings = ['utf-8', 'windows-1250', 'windows-1252' ...etc]
for e in encodings:
try:
fh = codecs.open('file.txt', 'r', encoding=e)
fh.readlines()
fh.seek(0)
except UnicodeDecodeError:
print('got unicode error with %s , trying different encoding' % e)
else:
print('opening the file with encoding: %s ' % e)
break
Dưới đây là một ví dụ về đọc và lấy theo mệnh giá chardet
dự đoán mã hóa, đọc n_lines
từ tệp trong trường hợp nó lớn.
chardet
cũng cung cấp cho bạn một xác suất (nghĩa là confidence
) dự đoán mã hóa của nó (chưa xem cách họ đưa ra điều đó), được trả về với dự đoán của nó từ đó chardet.predict()
, vì vậy bạn có thể làm việc theo cách nào đó nếu bạn muốn.
def predict_encoding(file_path, n_lines=20):
'''Predict a file's encoding using chardet'''
import chardet
# Open the file as binary data
with open(file_path, 'rb') as f:
# Join binary lines for specified number of lines
rawdata = b''.join([f.readline() for _ in range(n_lines)])
return chardet.detect(rawdata)['encoding']
def predict_encoding(file_path, n=20): ... skip ... and then rawdata = b''.join([f.read() for _ in range(n)])
Đã thử chức năng này trên Python 3.6, hoạt động hoàn hảo với các mã hóa "ascii", "cp1252", "utf-8", "unicode". Vì vậy, đây chắc chắn là upvote.
# Function: OpenRead(file)
# A text file can be encoded using:
# (1) The default operating system code page, Or
# (2) utf8 with a BOM header
#
# If a text file is encoded with utf8, and does not have a BOM header,
# the user can manually add a BOM header to the text file
# using a text editor such as notepad++, and rerun the python script,
# otherwise the file is read as a codepage file with the
# invalid codepage characters removed
import sys
if int(sys.version[0]) != 3:
print('Aborted: Python 3.x required')
sys.exit(1)
def bomType(file):
"""
returns file encoding string for open() function
EXAMPLE:
bom = bomtype(file)
open(file, encoding=bom, errors='ignore')
"""
f = open(file, 'rb')
b = f.read(4)
f.close()
if (b[0:3] == b'\xef\xbb\xbf'):
return "utf8"
# Python automatically detects endianess if utf-16 bom is present
# write endianess generally determined by endianess of CPU
if ((b[0:2] == b'\xfe\xff') or (b[0:2] == b'\xff\xfe')):
return "utf16"
if ((b[0:5] == b'\xfe\xff\x00\x00')
or (b[0:5] == b'\x00\x00\xff\xfe')):
return "utf32"
# If BOM is not provided, then assume its the codepage
# used by your operating system
return "cp1252"
# For the United States its: cp1252
def OpenRead(file):
bom = bomType(file)
return open(file, 'r', encoding=bom, errors='ignore')
#######################
# Testing it
#######################
fout = open("myfile1.txt", "w", encoding="cp1252")
fout.write("* hi there (cp1252)")
fout.close()
fout = open("myfile2.txt", "w", encoding="utf8")
fout.write("\u2022 hi there (utf8)")
fout.close()
# this case is still treated like codepage cp1252
# (User responsible for making sure that all utf8 files
# have a BOM header)
fout = open("badboy.txt", "wb")
fout.write(b"hi there. barf(\x81\x8D\x90\x9D)")
fout.close()
# Read Example file with Bom Detection
fin = OpenRead("myfile1.txt")
L = fin.readline()
print(L)
fin.close()
# Read Example file with Bom Detection
fin = OpenRead("myfile2.txt")
L =fin.readline()
print(L) #requires QtConsole to view, Cmd.exe is cp1252
fin.close()
# Read CP1252 with a few undefined chars without barfing
fin = OpenRead("badboy.txt")
L =fin.readline()
print(L)
fin.close()
# Check that bad characters are still in badboy codepage file
fin = open("badboy.txt", "rb")
fin.read(20)
fin.close()
Tùy thuộc vào nền tảng của bạn, tôi chỉ chọn sử dụng file
lệnh shell linux . Điều này làm việc cho tôi vì tôi đang sử dụng nó trong một tập lệnh chỉ chạy trên một trong các máy linux của chúng tôi.
Rõ ràng đây không phải là một giải pháp hay câu trả lời lý tưởng, nhưng nó có thể được sửa đổi để phù hợp với nhu cầu của bạn. Trong trường hợp của tôi, tôi chỉ cần xác định xem một tệp có phải là UTF-8 hay không.
import subprocess
file_cmd = ['file', 'test.txt']
p = subprocess.Popen(file_cmd, stdout=subprocess.PIPE)
cmd_output = p.stdout.readlines()
# x will begin with the file type output as is observed using 'file' command
x = cmd_output[0].split(": ")[1]
return x.startswith('UTF-8')
Về nguyên tắc, về nguyên tắc, không thể xác định mã hóa của tệp văn bản, trong trường hợp chung. Vì vậy, không có thư viện Python chuẩn để làm điều đó cho bạn.
Nếu bạn có kiến thức cụ thể hơn về tệp văn bản (ví dụ: đó là XML), có thể có các hàm thư viện.
Nếu bạn biết một số nội dung của tệp, bạn có thể thử giải mã nó bằng một vài mã hóa và xem cái nào còn thiếu. Nói chung, không có cách nào vì tệp văn bản là tệp văn bản và những tệp đó là ngu ngốc;)
Trang web này có mã python để nhận dạng ascii, mã hóa bằng boms và utf8 no bom: https://unicodebook.readthedocs.io/guess_encoding.html . Đọc tệp thành mảng byte (dữ liệu): http://www.codecodex.com/wiki/Read_a_file_into_a_byte_array . Đây là một ví dụ. Tôi đang ở osx.
#!/usr/bin/python
import sys
def isUTF8(data):
try:
decoded = data.decode('UTF-8')
except UnicodeDecodeError:
return False
else:
for ch in decoded:
if 0xD800 <= ord(ch) <= 0xDFFF:
return False
return True
def get_bytes_from_file(filename):
return open(filename, "rb").read()
filename = sys.argv[1]
data = get_bytes_from_file(filename)
result = isUTF8(data)
print(result)
PS /Users/js> ./isutf8.py hi.txt
True
chardet
tham khảo. Có vẻ tốt, mặc dù hơi chậm.