Добрый день уважаемому сообществу !
Помогите разобраться со следующей проблемой.
На обработку поступает массив строк. Нужно определить кодировку строк - либо ANSI, либо Unicode.
Работа идет в среде Embarcadero Delphi RAD Studio 10.
Этот массив строк хранится в компоненте TStringList.
Если строки вводятся из файла прямо в TStringList, то для этого случая имеется демонстрационный код, работающий на ура :
procedure TForm2.Btn1Click(Sender: TObject);
var
ListStr : TStringList;
StrNameCod : UnicodeString;
LEncoding : TEncoding;
begin
ListStr := TStringList.Create();
ListStr.Clear();
case RG.ItemIndex of
0 : ListStr.LoadFromFile( 'c:\ ... ' ); // Вводим файл с текстом в кодировке ANSI
1 : ListStr.LoadFromFile( 'c:\ ... ' ); // Вводим файл с текстом в кодировке Unicode
end;
LEncoding := ListStr.Encoding;
StrNameCod := LEncoding.EncodingName; // получаем имя кодировки текста
Memo1.Clear();
Memo1.Lines.AddStrings( ListStr );
Memo2.Clear();
Memo2.Lines.Add( StrNameCod ); // выводим на отображение имя кодировки текста
ListStr.Free();
end;
А вот в случае, если строки в TStringList загружаются не прямо из файла, а из какого-то стороннего источника
( допустим - из другого компонента ), то свойство ListStr.Encoding не работает :
procedure TForm2.Btn2Click(Sender: TObject);
var
ListStr : TStringList;
StrNameCod : UnicodeString;
i : Integer;
LEncoding : TEncoding;
begin
// Сперва загружаем из файла строки в Memo, а затем переписываем их в StringList
// ( имтация передачи в StringList из стороннего источника )
case RG.ItemIndex of
0 : Memo1.Lines.LoadFromFile( 'c:\ ... ' ); // Вводим файл с текстом в кодировке ANSI
1 : Memo1.Lines.LoadFromFile( 'c:\ ... ' ); // Вводим файл с текстом в кодировке Unicode
end;
LEncoding := TEncoding.Create();
ListStr := TStringList.Create();
ListStr.Clear();
ListStr.AddStrings( Memo1.Lines );
// for i := 0 to Memo1.Lines.Count - 1 do
// ListStr.Add( Memo1.Lines.Strings[ i ] );
При присвоении StrNameCod значения непосредственно от ListStr.Encoding.EncodingName, либо через LEncoding.EncodingName
приложение аварийно вылетает с исключением.
При таких условиях ( строки вводятся не из файла ) свойство ListStr.Encoding не работает, или я чго-то не так делаю ?
Починить как-то можно ?
Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
05-10-2022 05:38
Python, я в силу сложившихся обстоятельств очень долго не заглядывал сюда, и только сейчас обнаружил ваш пост.
сам факт наличия BOM попортит логику работы программы и нервы какому-то другому программисту, например, лично я уже кушал проблему, что программы с .h файлами на сишечке не всеми компиляторами собираются, если в начале .h файла есть BOM - как раз потому, что BOM после обработки препроцессором попадает чёрт знает куда и ломает работу последующих модулей...
Мне интересна проблема, изложенная вами в цитате, поскольку и сам работаю с С++, хотя это и не имеет прямое отношение к обсуждаемому.
А что, если для исключения описанной проблемы сборки компиляторами придерживаться жесткого правила - все собираемые файлы должны быть в кодировке ANSI, пусть даже для этого и придется их перевести в таковую кодировку вручную ?
21-08-2022 04:54 | Комментарий к предыдущим ответам
Вся беда в том, что многие файлы "собираются" из кучи других файлов методов include (прямого включения), такие как конфиги, PHP скрипты и куча всего остального. Потому, оказывается, что BOM для таких файлов вреден. Ну и плюс линуксоиды воду мутят, будучи уверены, что "раз в нашей ОС, занимающей 2% рынка по дефолту UTF-8, то и нечего указывать его и баловаться со всякими BOM, если в файле первые, скажем, 1килобайт текста декодируются как UTF-8 - значит, весь файл UTF-8 и весь сказ".
Понятно, что точка зрения очень сильно так себе, но проблема с тем, что действительно не во всех файлах есть BOM и не везде его в принципе можно внедрить отсаётся. Так, из-за того, что при прямом склеивании BOM окажется где-то внутри файла, сам факт наличия BOM попортит логику работы программы и нервы какому-то другому программисту, например, лично я уже кушал проблему, что программы с .h файлами на сишечке не всеми компиляторами собираются, если в начале .h файла есть BOM - как раз потому, что BOM после обработки препроцессором попадает чёрт знает куда и ломает работу последующих модулей... правда, есть обход: первую строчку файла оставлять пустой, но это не всегда выход.
Так что такие дела, полагаться на BOM не стоит, но и пагубно считать всё подряд UTF-8 тоже неверно. Лучше дать право пользователю выбирать, как в Sublime: кодировка по умолчанию (UTF-8) и кодировка отката (Fallback encoding), когда не удаётся декодировать файл как UTF-8 - используем CP-1251. Ну либо совсем просто: всё, что не имеет BOM - CP-1251, пока пользователь не поменяет своё мнение.
16-05-2022 23:54 | Комментарий к предыдущим ответам
KotAlex, это файлы, сформированные различными программами, например, логи. А так же, всевозможные скрипты, xml, json. Я лишь хотел обратить внимание, что BOM - не 100% гарантия. Возможно, автор вопроса с такими файлами не работает.
Из моего опыта множество Unicode файлов не содержат BOM.
Разве ?????
Я вот беру первый же попавшийся под руку простой текстовый файл с текстом в Unicode и смотрю его в Total Kommander по F3 в режиме отображения в шестнадцатиричном коде - при этом ну очень явно видны два самых первых байта в начале файла, не имеющие никакого отношения к тексту. Значения этих байтов, правда, - лес темный, но в контексте данного обсуждения это и не имеет никакого значения ...
12-05-2022 02:21 | Комментарий к предыдущим ответам
Из моего опыта множество Unicode файлов не содержат BOM. Думаю, что надёжнее "огород" со статистикой и (или) анализом. Например, на последовательности, которые присущи определенной кодировке.
Подозреваю, что после чтения из файла кодировка правильно определяется, потому что в файле есть BOM (Byte Order Mark — несколько байт в начале файла, указывающих на использованную кодировку). Проверьте свои файлы, с которыми всё нормально работает низкоуровневым вьюером).
Да, все именно так и обстоит. Можно, к примеоу, посмотреть текстовый файл с кодировкой Unicode в Total Kommander по F3 в шестнадцатиричном коде - видно, что два первые байта не имеют отношения к тексту.
Именно поэтому и имеется возможность формально определить кодировку по этим байтам, но только при вводе из файла !
Если вводим отдельные строки в Unicode, то такого формального признака нет, определять нечем ...
до выполнения чтения из файла или потока,значение свойства Encoding равно nil, поэтому и исключение вылетает. Исключение какое? Если Access violation, то стопудово в этом причина?
Да, вы правы. Действительно, свойство Encoding равно nil изначально, поэтому, если нет ввода из файла, то при обращении к нему и вылетает исключение именно ACCESS VIOLATION.
В-общем, жаль. Так хотелось иметь какой-то формальный признак наличия кодировки Unicode, а не городить самому огород с распознаванием кодировки ...
Спасибо за ответ.
Подозреваю, что после чтения из файла кодировка правильно определяется, потому что в файле есть BOM (Byte Order Mark — несколько байт в начале файла, указывающих на использованную кодировку). Проверьте свои файлы, с которыми всё нормально работает низкоуровневым вьюером).
Хм... читайте хелп — источник знаний :-)
Encoding is a read-only property that contains the value of the character encoding detected when the LoadFromStream or LoadFromFile methods are called. If a file or stream does not contain a BOM (the encoding value cannot be detected) then Encoding is set to the value specified in the DefaultEncoding property.
То есть, у TStrings есть свойство только для чтения Encoding, которое содержит кодировку, определенную при выполнении методов LoadFromStream или LoadFromFile. Если в файле или потоке отсутствует BOM, в Encoding заносится значение, определенное в свойстве DefaultEncoding.
Исходников Эмбаркадеры нет сейчас под рукой, но, подозреваю, что до выполнения чтения из файла или потока,значение свойства Encoding равно nil, поэтому и исключение вылетает. Исключение какое? Если Access violation, то стопудово в этом причина?
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.