LINUX.ORG.RU

чтение любого файла так, как будто он utf-8

 ,


0

1

Я хочу открывать любой файл так, как будто он utf-8. При этом в реальности там может быть смесь двоичных данных и utf-8. Хочу алгоритм, который будет читать любой файл без потери данных, а utf-8 читать как последовательность символов юникода.

Предлагается такой алгоритм:

Пытаемся читать символ юникода. Если получилось, то ок. Если не получилось, то мы прочитали сколько-то (не более 5-6) байт, и дальше поняли, что что-то пошло не так. В этом случае, мы для каждого байта возвращаем знак-заменитель U+FFFD � , а за ним символ юникода с кодом, численно равным этому байту (как 8-разрядному беззнаковому целому). Если попался просто знак-заменитель, то мы его удваиваем. В итоге, независимо от того, является ли данный поток правильным utf-8, с ошибками, или вообще не utf-8, наш «чтец» вернёт всю информацию, которая была в потоке, без потерь.

Вопросы:

  • не изобрёл ли я велосипед?
  • нужно ли что-то делать с особыми кодами, U+FFFE, U+FFFF?
  • какие грабли я не предусмотрел?
★★★★★

Я хочу открывать любой файл так, как будто он utf-8

Ну так открывай файл и читай. Что ТС хочет? Мне непонятно.

Может ТС хочет что-то другое. Например, «Я хочу отобразить в виде набора символов(глифов) на экране в текстовом/графическом режиме некие данные, думая, что это обычный utf-8 текст, даже, если фактически это не так.»

Или, «Я хочу в любых рандомных бинарных данных вычленять символы utf-8».

pathfinder ★★★ ()
Ответ на: комментарий от aidaho

Мне напомнило hexdump на стероидах, unidump:

$ cat test 
в и д е т ь

$ hexdump -C test
00000000  d0 b2 20 d0 b8 20 d0 b4  20 d0 b5 20 d1 82 20 d1  |.. .. .. .. .. .|
00000010  8c 0a                                             |..|
00000012

$ pip install unidump

$ unidump test
      0    0432 0020 0438 0020 0434 0020 0435 0020 0442 0020 044C 000A                        в.и.д.е.т.ь.

(echo -n -e '\xf0\x9f\xa7\x9d\xf0\x9f\x8f\xbd\xe2' ; echo -n -e '\x80\x8d\xe2\x99\x82\xef\xb8\x8f' ; ) | unidump -n 5
      0    1F9DD 1F3FD 200D 2642 FE0F    🧝🏽.♂️

Автор бы нормально изложил свои мысли.

EXL ★★★★★ ()
Ответ на: комментарий от hakavlad

Например:

$ rawcat /proc/meminfo
['MemTotal:       10022976 kB\nMemFree:         4550108 kB\nMemAvailable:    7256068 kB\nBuffers:          315380 kB\nCached:          2941628 kB\nSwapCached:            0 kB\nActive:          1537024 kB\nInactive:        3358552 kB\nActive(anon):      11940 kB\nInactive(anon):  2009472 kB\nActive(file):    1525084 kB\nInactive(file):  1349080 kB\nUnevictable:      196300 kB\nMlocked:             628 kB\nSwapTotal:             0 kB\nSwapFree:              0 kB\nDirty:              5084 kB\nWriteback:             0 kB\nAnonPages:       1835260 kB\nMapped:           706924 kB\nShmem:            382584 kB\nKReclaimable:     126604 kB\nSlab:             202716 kB\nSReclaimable:     126604 kB\nSUnreclaim:        76112 kB\nKernelStack:       16640 kB\nPageTables:        75268 kB\nNFS_Unstable:          0 kB\nBounce:                0 kB\nWritebackTmp:          0 kB\nCommitLimit:     5011488 kB\nCommitted_AS:    9056816 kB\nVmallocTotal:   34359738367 kB\nVmallocUsed:       38484 kB\nVmallocChunk:          0 kB\nPercpu:             6848 kB\nHardwareCorrupted:     0 kB\nAnonHugePages:      2048 kB\nShmemHugePages:        0 kB\nShmemPmdMapped:        0 kB\nFileHugePages:         0 kB\nFilePmdMapped:         0 kB\nHugePages_Total:       0\nHugePages_Free:        0\nHugePages_Rsvd:        0\nHugePages_Surp:        0\nHugepagesize:       2048 kB\nHugetlb:               0 kB\nDirectMap4k:      396028 kB\nDirectMap2M:     9904128 kB\n']


hakavlad ★★★ ()
Ответ на: комментарий от hakavlad

Или:

$ rawcat /bin/sh [’\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00>\x00\x01\x00\x00\x007\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00\x18\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x008\x00\t\x00@\x00\x1b\x00\x1a\x00\x06\x00\x00\x00\x05\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x008\x02\x00\x00\x00\x00\x00\x008\x02\x00\x00\x00\x00\x00\x008\x02\x00\x00\x00\x00\x00\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00\x01\x00\x00\x00\x00\x00!\x00\x00\x00\x00\x00!\x00\x00\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00>\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x02\x00\x00\x00\x06\x00\x00\x00h\x01\x00\x00\x00\x00\x00h!\x00\x00\x00\x00\x00h!\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00T\x02\x00\x00\x00\x00\x00\x00T\x02\x00\x00\x00\x00\x00\x00T\x02\x00\x00\x00\x00\x00\x00D\x00\x00\x00\x00\x00\x00\x00D\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00Ptd\x04\x00\x00\x00\x04f\x01\x00\x00\x00\x00\x00\x04f\x01\x00\x00\x00\x00\x00\x04f\

hakavlad ★★★ ()

не изобрёл ли я велосипед

Ты изобрел велосипед с квадратными колесами. Зачем вообще за пользователя твоего языка выбирать как именно читать файл? Сделай как и во всех других языках две опции чтения файлы.

  1. как байты
  2. как текст

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

Aswed ★★★★★ ()

Мне кажется, сама задача изложено чётко. Думаю, вы спрашиваете, зачем такая задача нужна?

Отвечаю: как минимум, нужна для универсального просмотровщика файлов, для случаев, когда нельзя угадать кодировку и она неизвестна из контекста. В A2 может быть и ситуация, когда часть файла - валидный utf-8, но она окружена бинарными данными (формат Оберон устроен именно так).

В этом случае, падать и отказываться открывать файл - это плохо. Заменять непонятое на символы-заместители - чуть лучше, но тоже не фонтан.

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

Как-то так.

den73 ★★★★★ ()
Ответ на: комментарий от EXL

Да, спасибо, это более-менее: «Invalid byte sequences are represented with an “X” and with the hex value en- closed in question marks, e.g., “?F5?”.» - «Некорректные последовательности байт представлены как X и как 16-ричные значения, окружённые знаками вопроса». Единственное, что в моём алгоритме достаточно только одного представления, а не двух, не считая того, что знаки юникода между собой, вообще говоря, визуально неотличимы. Но это уже другое измерение проблемы.

den73 ★★★★★ ()

Да вроде всё понятно и нормально. Ты по одному байту собираешься читать, если там не UTF-8? Если по одному, я бы взял что-то вроде 0xff_ff_ff_nn.

Legioner ★★★★★ ()
Ответ на: комментарий от den73

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

AKonia ★★ ()

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

Такого не существует. Придется ограничить множество всех возможных файлов хотя бы до множества формат которых известен.

anonymous ()

Всем спасибо, прихожу к выводу, что вроде норм. Объясню, что отличие от 16-ричного просмотровщика с распознованием utf-8 в том, что данный просмотровщик предполагается одноколоночным. Т.е. это даже не просмотровщик, а просто интерфейс «чтеца» для ввода данных из потока. Впрочем, я про это и в начале темы написал.

den73 ★★★★★ ()
Последнее исправление: den73 (всего исправлений: 1)

Извиняюсь за небольшой оффтоп

Господа, верно ли предположение - все управляющие диапазоны символов в юникоде умещаются в ASCII набор (C0, C1). Все остальные символы (возможно составленные из комбинаций из нескольких code point’ов) занимают строго одно знакоместо на экране. Т.е. не будет какого-нибудь U+100500 - горизонтальный таб на 5 знакомест. Или какой-нибудь цветной какашки на 2-4 знакоместа.

Дело имею с ЮТФ-8. Мне нужна простая вещь - один код поинт (возможно комбинация), одно знакоместо. С ASCII набором вопросов нет, комбинации читаю через boost.locale. Недавно обнаружил, что эти наркоманы начали пихать какие-то управляющие символы выше ASCII, например U+2028 LINE SEPARATOR, но печатается пробелом с одним знакоместом. Но вот если встретится какой-нибудь горизонтальнай таб, то это будет подстава.

anonymous ()