Подтвердить что ты не робот

Как проверить, действительно ли файл UTF-8?

Я обрабатываю некоторые файлы данных, которые должны быть действительными UTF-8, но это не так, что приводит к сбою синтаксического анализатора (не под моим контролем). Я хотел бы добавить этап предварительной проверки данных для правильного формирования UTF-8, но я еще не нашел утилиту, чтобы помочь сделать это.

На W3C есть веб-служба, которая кажется мертвой, и я нашел инструмент проверки только для Windows, который сообщает о недействительных файлах UTF-8, но не сообщает, какие строки/символы нужно исправить.

Я был бы рад либо инструменту, который я могу вставить и использовать (в идеале кроссплатформенный), либо сценарию ruby /perl, который я могу сделать частью моего процесса загрузки данных.

4b9b3361

Ответ 1

Вы можете использовать GNU iconv:

$ iconv -f UTF-8 your_file -o /dev/null; echo $?

Или с более старыми версиями iconv, такими как в macOS:

$ iconv -f UTF-8 your_file > /dev/null; echo $?

Команда вернет 0, если файл может быть успешно преобразован, и 1, если нет. Кроме того, он распечатает смещение байта, в котором произошла неправильная последовательность байтов.

Редактировать: выходную кодировку не нужно указывать, предполагается, что это UTF-8.

Ответ 2

Использовать функции python и str.encode | декодирования.

>>> a="γεια"
>>> a
'\xce\xb3\xce\xb5\xce\xb9\xce\xb1'
>>> b='\xce\xb3\xce\xb5\xce\xb9\xff\xb1' # note second-to-last char changed
>>> print b.decode("utf_8")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.5/encodings/utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode byte 0xff in position 6: unexpected code byte

Исключенное исключение содержит запрошенную информацию в свойстве .args.

>>> try: print b.decode("utf_8")
... except UnicodeDecodeError, exc: pass
...
>>> exc
UnicodeDecodeError('utf8', '\xce\xb3\xce\xb5\xce\xb9\xff\xb1', 6, 7, 'unexpected code byte')
>>> exc.args
('utf8', '\xce\xb3\xce\xb5\xce\xb9\xff\xb1', 6, 7, 'unexpected code byte')

Ответ 3

Вы можете использовать isutf8 из коллекции moreutils.

$ apt-get install moreutils
$ isutf8 your_file

В сценарии оболочки используйте переключатель --quiet и проверьте состояние выхода, которое равно нулю для файлов, которые являются допустимыми utf-8.

Ответ 4

Как насчет библиотеки gnu iconv? Использование функции iconv(): "На входе встречается недопустимая многобайтовая последовательность. В этом случае она устанавливает errno в EILSEQ и возвращает (size_t) (- 1). * Inbuf остается указателем на начало недопустимой многобайтовой последовательности."

EDIT: oh - я пропустил ту часть, где вы хотите использовать язык сценариев. Но для работы в командной строке утилита iconv также должна быть проверена для вас.

Ответ 5

Код С++ ниже основан на одном, опубликованном на многих сайтах через Интернет. Я исправил ошибку в исходном коде и добавил возможность получить как недопустимый символ, так и недопустимый символ.

///Returns -1 if string is valid. Invalid character is put to ch.
int getInvalidUtf8SymbolPosition(const unsigned char *input, unsigned char &ch) {
  int                 nb, na;
  const unsigned char *c = input;

  for (c = input;  *c;  c += (nb + 1)) {
    if (!(*c & 0x80))
        nb = 0;
    else if ((*c & 0xc0) == 0x80)
    {
        ch = *c;
        return (int)c - (int)input;
    }
    else if ((*c & 0xe0) == 0xc0)
        nb = 1;
    else if ((*c & 0xf0) == 0xe0)
        nb = 2;
    else if ((*c & 0xf8) == 0xf0)
        nb = 3;
    else if ((*c & 0xfc) == 0xf8)
        nb = 4;
    else if ((*c & 0xfe) == 0xfc)
        nb = 5;
    na = nb;
    while (na-- > 0)
      if ((*(c + nb) & 0xc0) != 0x80)
      {
          ch = *(c + nb);
          return (int)(c + nb) - (int)input;
      }
  } 

  return -1;
}