Kodlanmış bazı metinler aldım, ancak hangi karakter kümesinin kullanıldığını bilmiyorum. Python kullanarak bir metin dosyasının kodlamasını belirlemenin bir yolu var mı? Bir metin dosyasının kodlama / kod sayfasını C # ile nasıl ele alabilirim .
Kodlanmış bazı metinler aldım, ancak hangi karakter kümesinin kullanıldığını bilmiyorum. Python kullanarak bir metin dosyasının kodlamasını belirlemenin bir yolu var mı? Bir metin dosyasının kodlama / kod sayfasını C # ile nasıl ele alabilirim .
Yanıtlar:
Kodlamanın her zaman doğru bir şekilde algılanması mümkün değildir .
(Chardet SSS'den :)
Ancak, bazı kodlamalar belirli diller için optimize edilmiştir ve diller rastgele değildir. Bazı karakter dizileri her zaman açılırken, diğer diziler anlamsızdır. Bir gazete açan ve “txzqJv 2! Dasd0a QqdKjvz” bulan akıcı bir kişi, İngilizce olmadığını anlar (tamamen İngilizce harflerden oluşmasına rağmen). Bir çok "tipik" metin üzerinde çalışarak, bir bilgisayar algoritması bu tür akıcılığı simüle edebilir ve bir metnin dili hakkında eğitimli bir tahminde bulunabilir.
Orada Chardet kullandığı çalışma kodlayan algılamak için denemek için o kütüphane. chardet, Mozilla'daki otomatik algılama kodunun bir bağlantı noktasıdır.
UnicodeDammit'i de kullanabilirsiniz . Aşağıdaki yöntemleri deneyecek:
Kodlamayı çözmek için başka bir seçenek libmagic kullanmaktır ( dosya komutunun arkasındaki koddur ). Mevcut python bağları bolluğu vardır.
Dosya kaynak ağacında yaşayan python bağlamaları python-magic (veya python3-magic ) debian paketi olarak mevcuttur. Bir dosyanın kodlamasını yaparak şunları yapabilir:
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
Pypi'de aynı şekilde adlandırılan, ancak uyumsuz bir python-magic pip paketi var libmagic
. Ayrıca, kodlamayı da yapabilir:
import magic
blob = open('unknown-file', 'rb').read()
m = magic.Magic(mime_encoding=True)
encoding = m.from_buffer(blob)
libmagic
gerçekten de uygulanabilir bir alternatiftir chardet
. Ve farklı paketler hakkında harika bilgiler python-magic
! Eminim bu belirsizlik birçok insanı ısırır
file
metin dosyalarındaki insan dilini tanımlamada özellikle iyi değildir. Çeşitli kapsayıcı formatlarını tanımlamak için mükemmeldir, ancak bazen bunun ne anlama geldiğini bilmek zorundasınız ("Microsoft Office belgesi" bir Outlook mesajı, vb. Anlamına gelebilir).
open()
: UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfc in position 169799: invalid start byte
. Kodlayan vim yıllardan göre dosya :set fileencoding
olup latin1
.
errors='ignore'
örnek kodun çıktısı daha az yardımcı olur binary
.
Bazı kodlama stratejileri, lütfen tadına bakın:
#!/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
Dosyayı bir döngü biçiminde açıp okuyarak kodlamayı kontrol etmek isteyebilirsiniz ... ancak önce dosya boyutunu kontrol etmeniz gerekebilir:
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
io
gibi io.open(filepath, 'r', encoding='utf-8')
çünkü daha uygun olan codecs
dönüştürmez \n
okuma ve yazma üzerine otomatik. HERE
Aşağıda, chardet
kodlama tahminini okuma ve alma değerinin n_lines
büyük olması durumunda dosyadan okuma örneği verilmiştir .
chardet
Ayrıca, confidence
kodlama tahmini (bunun nasıl ortaya çıktıklarına bakmadım) olasılığı da verir , bu da onun tahmini ile döndürülür chardet.predict()
, böylece isterseniz bir şekilde çalışabilirsiniz.
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)])
Python 3.6 üzerinde bu işlevi denedim, "ascii", "cp1252", "utf-8", "unicode" kodlamaları ile mükemmel çalıştı. Yani bu kesinlikle 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()
Platformunuza bağlı olarak, linux shell file
komutunu kullanmayı tercih ediyorum . Özellikle benim linux makinelerimizden birinde çalışan bir senaryoda kullandığım için bu benim için çalışıyor.
Açıkçası bu ideal bir çözüm veya cevap değildir, ancak ihtiyaçlarınıza uyacak şekilde değiştirilebilir. Benim durumumda sadece bir dosyanın UTF-8 olup olmadığını belirlemem gerekiyor.
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')
Prensipte, bir metin dosyasının kodlamasını genel durumda belirlemek imkansızdır. Yani hayır, bunu sizin için yapacak standart bir Python kütüphanesi yok.
Metin dosyası hakkında daha spesifik bilgiye sahipseniz (ör. XML olduğu), kütüphane işlevleri olabilir.
Dosyanın bazı içeriğini biliyorsanız birkaç kodlamayla kodunu çözmeyi ve hangisinin eksik olduğunu görmeyi deneyebilirsiniz. Genel olarak, bir metin dosyası bir metin dosyası olduğundan ve bunlar aptal olduğu için bir yol yoktur;)
Bu site, ASCII'yi tanımak, bombalarla kodlamak ve utf8 bom yok: https://unicodebook.readthedocs.io/guess_encoding.html . Dosyayı bayt dizisine (veri) okuyun: http://www.codecodex.com/wiki/Read_a_file_into_a_byte_array . İşte bir örnek. Osx'tayım.
#!/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
Referans için teşekkürler . Biraz yavaş olmasına rağmen iyi görünüyor.