Как определить кодировку текста?

Я получил кодированный текст, но я не знаю, какая кодировка использовалась. Есть ли способ определить кодировку текстового файла с помощью Python? Как я могу определить кодировку / кодовую страницу текстового файла имеет дело с C#.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
242
0
272 663
10
Перейти к ответу Данный вопрос помечен как решенный

Ответы 10

Определить кодировку текстового файла в общем случае в принципе невозможно. Так что нет, стандартной библиотеки Python для этого не существует.

Если у вас есть более конкретные знания о текстовом файле (например, что это XML), могут быть библиотечные функции.

Если вам известно какое-то содержимое файла, вы можете попытаться декодировать его с помощью нескольких кодировок и посмотреть, какая из них отсутствует. В общем, нет никакого способа, так как текстовый файл - это текстовый файл, а это глупо;)

Ответ принят как подходящий

Обновлено: chardet, похоже, не поддерживается, но большая часть ответа применима. Проверьте https://pypi.org/project/charset-normalizer/ для альтернативы

Правильное определение кодировки всегда - невозможно.

(Из FAQ по chardet :)

However, some encodings are optimized for specific languages, and languages are not random. Some character sequences pop up all the time, while other sequences make no sense. A person fluent in English who opens a newspaper and finds “txzqJv 2!dasd0a QqdKjvz” will instantly recognize that that isn't English (even though it is composed entirely of English letters). By studying lots of “typical” text, a computer algorithm can simulate this kind of fluency and make an educated guess about a text's language.

Существует библиотека Chardet, которая использует это исследование, чтобы попытаться обнаружить кодировку. chardet - это порт кода автоопределения в Mozilla.

Вы также можете использовать Юникод. Он попробует следующие методы:

  • Кодировка, обнаруженная в самом документе: например, в объявлении XML или (для документов HTML) в теге META http-Equiv. Если Beautiful Soup обнаружит такую ​​кодировку в документе, он снова проанализирует документ с самого начала и попробует новую кодировку. Единственное исключение - если вы явно указали кодировку, и эта кодировка действительно сработала: тогда она будет игнорировать любую кодировку, найденную в документе.
  • Кодировка, полученная при просмотре первых нескольких байтов файла. Если на этом этапе обнаруживается кодировка, это будет одна из кодировок UTF- *, EBCDIC или ASCII.
  • Кодировка, прослушанная библиотекой Chardet, если она у вас установлена.
  • UTF-8
  • Окна-1252

Спасибо за ссылку на chardet. Вроде неплохо, хотя немного медленнее.

Craig McQueen 28.01.2010 08:15

Не удавалось все время определять кодировку ... разве это не ошибка стандарта кодирования? Разве это не должно быть всегда предсказуемо?

Geomorillo 02.12.2013 01:40

@Geomorillo: Не существует такой вещи, как «стандарт кодирования». Кодирование текста такое же старое, как и компьютерные технологии, оно органично росло со временем и потребностями, это не планировалось. «Юникод» - это попытка исправить это.

nosklo 02.12.2013 18:34

И неплохой, учитывая все обстоятельства. Я хотел бы знать, как мне узнать, с какой кодировкой был открыт открытый текстовый файл?

holdenweb 14.03.2014 10:27

Меня это смущает. У меня есть текстовый файл, который я с трудом читал на Python, поэтому я открыл его в Visual Studio Code. В нижней части окна результирующего файла написано «UTF-16 LE». Когда вы замечаете, что это невозможно, означает ли это, что такие инструменты, как VSCode, тоже выйдут из строя?

dumbledad 20.04.2018 13:28

@dumbledad я сказал, что правильно определить все время невозможно. Все, что вы можете сделать, это предположить, но иногда это может не получиться, это не сработает каждый раз из-за того, что кодировки не обнаруживаются. Чтобы сделать предположение, вы можете использовать один из инструментов, которые я предложил в ответе.

nosklo 20.04.2018 18:41
chardet имеет действительно хороший интерфейс командной строки, я не уверен насчет вашего варианта использования, для меня я действительно просто пытался угадать кодировку файла на лету, а не использовать это в скрипте или чем-то еще. чтобы использовать параметр CLI (после pip install chardet) $ chardet filename, и вы можете использовать предполагаемую кодировку для кодирования вашего текстового файла в другие параметры, используя такие инструменты, как iconv.
adonese 31.08.2018 22:40

Мне бы очень понравился chardet, но с тех пор, как была добавлена ​​поддержка турецкого языка, цифры были искажены так, что теперь он угадывает турецкий язык для слишком большого количества файлов, с которыми я сталкивался. Настолько, что мне пришлось избавиться от chardet.

Csaba Toth 10.01.2019 00:49

Видимо cchardet быстрее, но требует cython.

Superdooperhero 26.05.2019 22:48

Удивительно, что ни одно из ранее существовавших решений не помогло, но простая функция подойдет для большинства типичных случаев (и может быть настроена для ваших местных нужд): paste.zi.fi/p/decode.py/view

L. Kärkkäinen 12.07.2019 15:46

@ LasseKärkkäinen цель этого ответа - показать, что правильное определение кодировки - это невозможно; функция, которую вы предоставляете, может правильно угадать для вашего случая, но во многих случаях она неверна.

nosklo 12.07.2019 16:58

@nosklo Совершенно верно; поэтому в комментарии говорится о 8-битных догадках. Однако следует использовать разумные приоритеты, и теперь Шардет слишком отдает предпочтение турецкому пути. Паста демонстрирует явные проблемы с chardet, которые не могут быть оправданы двусмысленностью (потому что \ x81 не существует в "обнаруженной" кодировке и потому что UTF-8 всегда должен быть первым выбором, когда он подходит).

L. Kärkkäinen 15.07.2019 07:29

Вы можете добавить более свежий кодировка-нормализатор

snakecharmerb 31.08.2020 16:42

Некоторые стратегии кодирования, пожалуйста, раскомментируйте по вкусу:

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

Вы можете проверить кодировку, открыв и прочитав файл в виде цикла ... но вам может потребоваться сначала проверить размер файла:

#PYTHON
encodings = ['utf-8', 'windows-1250', 'windows-1252'] # add more
            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, например io.open(filepath, 'r', encoding='utf-8'), что более удобно, потому что codecs не конвертирует \n автоматически при чтении и записи. Подробнее о ЗДЕСЬ

Searene 01.05.2016 09:57

Другой вариант отработки кодировки - использовать libmagic (код, стоящий за Команда файл). Есть множество Доступны привязки python.

Привязки python, которые живут в дереве исходных файлов файлов, доступны как питон-магия (или python3-magic) пакет debian. Он может определить кодировку файла, выполнив:

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 есть одноименный, но несовместимый пакет pip питон-магия, который также использует libmagic. Он также может получить кодировку, выполнив:

import magic

blob = open('unknown-file', 'rb').read()
m = magic.Magic(mime_encoding=True)
encoding = m.from_buffer(blob)
libmagic действительно является жизнеспособной альтернативой chardet. И отличная информация об отдельных пакетах с именем python-magic! Я уверен, что эта двусмысленность многих укусит
MestreLion 22.10.2013 20:42
file не особенно хорошо распознает человеческий язык в текстовых файлах. Он отлично подходит для идентификации различных форматов контейнеров, хотя иногда вам нужно знать, что это означает («документ Microsoft Office» может означать сообщение Outlook и т. д.).
tripleee 06.03.2015 10:15

В поисках способа справиться с тайной кодировки файлов я нашел этот пост. К сожалению, используя пример кода, я не могу пройти мимо open(): UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfc in position 169799: invalid start byte. Кодировка файла согласно vim's :set fileencoding - latin1.

xtian 19.08.2017 18:51

Если я использую необязательный аргумент errors='ignore', вывод кода примера будет менее полезным binary.

xtian 19.08.2017 18:54

@xtian Вам нужно открыть в двоичном режиме, т.е. open ("filename.txt", "rb").

L. Kärkkäinen 15.07.2019 07:34

chardet не работает с iso-8859-1 (распространенный формат файлов Windows), но работает отлично! libmagic кажется лучшим решением этой проблемы.

cdignam 23.10.2019 20:11

второй решил мою проблему. И я должен использовать blob = open ("unknown-file", "rb"). Read (), как сказал Л. Кярккяйнен.

Xiaoqi 19.03.2020 10:03

Существует также пакет python-magic-bin, который имеет двоичные файлы и работает в Windows: github.com/julian-r/python-magic Этот пакет вернул двоичный код для кодировки файла .docx, в то время как UnicodeDammit вернул utf-8, а chardet вернул None. В этом случае лучше всего выглядит bs4 (UnicodeDammit).

wordsforthewise 01.02.2021 02:05
# 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()

В зависимости от вашей платформы я просто использую команду file оболочки linux. У меня это работает, так как я использую его в скрипте, который работает исключительно на одной из наших Linux-машин.

Очевидно, что это не идеальное решение или ответ, но его можно изменить в соответствии с вашими потребностями. В моем случае мне просто нужно определить, является ли файл UTF-8 или нет.

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

Разветвление нового процесса не требуется. Код Python уже выполняется внутри процесса и может сам вызывать нужные системные функции без дополнительных затрат на загрузку нового процесса.

vdboor 18.07.2017 13:15

Вот пример чтения и принятия за чистую монету предсказания кодирования chardet, чтения n_lines из файла, если он большой.

chardet также дает вам вероятность (например, confidence) его предсказания кодирования (не смотрел, как они это сделали), который возвращается вместе с его предсказанием от chardet.predict(), так что вы можете как-то поработать с этим, если хотите.

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']

Посмотрев на это после получения голосов «за», вы увидите, что это решение могло бы замедлиться, если бы в первой строке было много данных. В некоторых случаях было бы лучше читать данные по-другому.

ryanjdillon 22.01.2018 14:55

Я изменил эту функцию следующим образом: def predict_encoding(file_path, n=20): ... skip ... and then rawdata = b''.join([f.read() for _ in range(n)]) Испытал эту функцию на Python 3.6, отлично работал с кодировками «ascii», «cp1252», «utf-8», «unicode». Так что это определенно положительный голос.

n158 18.10.2018 14:59

это очень хорошо для обработки небольших наборов данных с различными форматами. Протестировал это рекурсивно в моем корневом каталоге, и он работал как удовольствие. Спасибо дружище.

Manakin 25.11.2019 15:48

Я не очень знаком с чтением данных на байтовом уровне. @ n158, есть ли шанс, что можно перестать читать байты в середине символа и запутать chardet?

kuzzooroo 28.03.2021 20:24

На этом сайте есть код Python для распознавания ascii, кодирования с помощью boms и utf8 no bom: https://unicodebook.readthedocs.io/guess_encoding.html. Считать файл в байтовый массив (данные): http://www.codecodex.com/wiki/Read_a_file_into_a_byte_array. Вот пример. Я в 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

Ссылка на решение приветствуется, но убедитесь, что ваш ответ полезен и без нее: добавить контекст вокруг ссылки, чтобы ваши коллеги-пользователи имели некоторое представление о том, что это такое и почему оно есть, а затем процитируйте наиболее релевантную часть страницы, на которую вы ссылаетесь. если целевая страница недоступна. Ответы, которые представляют собой не более чем ссылку, могут быть удалены.

double-beep 12.04.2019 17:11

Это может быть полезно

from bs4 import UnicodeDammit
with open('automate_data/billboard.csv', 'rb') as file:
   content = file.read()

suggestion = UnicodeDammit(content)
suggestion.original_encoding
#'iso-8859-1'

Другие вопросы по теме