web-dev-qa-db-fra.com

Comment déterminer l'encodage du texte?

J'ai reçu du texte codé, mais je ne sais pas quel jeu de caractères a été utilisé. Existe-t-il un moyen de déterminer l'encodage d'un fichier texte à l'aide de Python? Comment puis-je détecter l'encodage/la page de code d'un fichier texte traite avec C #.

166
Nope

Détecter correctement le codage à chaque fois est impossible.

(De chardet FAQ :)

Cependant, certains encodages sont optimisés pour des langues et des langues spécifiques ne sont pas aléatoires. Un peu de caractère les séquences apparaissent tout le temps, alors que d'autres séquences n'ont aucun sens. UNE personne qui parle couramment anglais et qui ouvre a journal et trouve «txzqJv 2! dasd0a QqdKjvz ”le reconnaîtra instantanément ce n'est pas l'anglais (même s'il est composé entièrement de lettres anglaises) . En étudiant beaucoup de texte «typique», a algorithme informatique peut simuler cela sorte de fluence et faire un instruit devinez à propos de la langue d'un texte.

Il y a la bibliothèque chardet qui utilise cette étude pour détecter le codage. chardet est un port du code de détection automatique dans Mozilla. 

Vous pouvez également utiliser UnicodeDammit . Il va essayer les méthodes suivantes:

  • Un codage découvert dans le document lui-même: par exemple, dans une déclaration XML ou (pour les documents HTML) une balise META http-equiv. Si Beautiful Soup trouve ce type d’encodage dans le document, il analyse à nouveau le document depuis le début et donne l’essai au nouvel encodage. La seule exception est si vous avez explicitement spécifié un encodage et que cet encodage a réellement fonctionné: il ignorera alors tout encodage trouvé dans le document.
  • Un encodage reniflé en regardant les premiers octets du fichier. Si un codage est détecté à ce stade, ce sera l'un des codages UTF- *, EBCDIC ou ASCII.
  • Un encodage reniflé par la bibliothèque chardet , si vous l'avez installé.
  • UTF-8
  • Windows-1252 
179
nosklo

Une autre option pour travailler sur l'encodage consiste à utiliser libmagic (qui est le code derrière la commande file ). Il existe une profusion de liaisons Python disponibles.

Les liaisons python présentes dans l’arborescence des sources de fichiers sont disponibles sous la forme du paquet python-magic (ou python3-magic ) Debian. Il peut déterminer l'encodage d'un fichier en faisant:

import magic

blob = open('unknown-file').read()
m = magic.open(magic.MAGIC_MIME_ENCODING)
m.load()
encoding = m.buffer(blob)  # "utf-8" "us-ascii" etc

Il y a un paquet pip python-magic au nom identique, mais incompatible, sur pypi qui utilise également libmagic. Il peut aussi obtenir l'encodage, en faisant:

import magic

blob = open('unknown-file').read()
m = magic.Magic(mime_encoding=True)
encoding = m.from_buffer(blob)
44
Hamish Downer

Quelques stratégies d’encodage, veuillez ne pas commenter au goût: 

#!/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

Vous voudrez peut-être vérifier l'encodage en ouvrant et en lisant le fichier sous la forme d'une boucle ... mais vous devrez peut-être d'abord vérifier la taille du fichier:

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              
23
zzart

Voici un exemple de lecture et de prise à la valeur apparente d'une prédiction de codage chardet, lisant n_lines à partir du fichier s'il est volumineux.

chardet vous donne également une probabilité (c'est-à-dire confidence) de sa prédiction d’encodage (n’a pas regardé comment elle aboutit), qui est renvoyée avec sa prédiction de chardet.predict(), afin que vous puissiez l’afficher si vous le souhaitez.

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']
12
ryanjdillon
# 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()
1
Bill Moore

Il est en principe impossible de déterminer le codage d'un fichier texte, dans le cas général. Donc non, il n'y a pas de bibliothèque Python standard pour le faire pour vous.

Si vous avez des connaissances plus spécifiques sur le fichier texte (par exemple, il s'agit de XML), il peut y avoir des fonctions de bibliothèque.

0
Martin v. Löwis

Si vous connaissez le contenu du fichier, vous pouvez essayer de le décoder avec plusieurs encodages et voir lequel est manquant. En général, il n'y a aucun moyen, car un fichier texte est un fichier texte et ceux-ci sont stupides;)

0
Martin Thurau

En fonction de votre plate-forme, je choisis simplement d'utiliser la commande linux Shell file. Cela fonctionne pour moi puisque je l'utilise dans un script qui s'exécute exclusivement sur l'une de nos machines Linux.

Évidemment, ce n'est pas la solution ou la réponse idéale, mais elle pourrait être modifiée pour répondre à vos besoins. Dans mon cas, je dois simplement déterminer si un fichier est au format UTF-8 ou non.

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')
0
MikeD