Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Не получили письмо с кодом активации?

Официальный форум Simple-Scada.

Автор Тема: Кодировка русского языка при записи в файл  (Прочитано 3660 раз)

Серега

  • Старожил
  • ****
  • Сообщений: 287
    • Просмотр профиля
Добрый день!
На форуме есть темы про кодировку (https://simple-scada.com/forum/index.php?action=search2) и это может кому-нибудь помочь.
В ходе работы над проектом возникла необходимость записывать некоторую информацию в файл.
Вот пример универсального скрипта, привязанный к событию Window.OnShow:
Код
if Assigned(aVar_LightWorking) then
  begin
    Button430.Variable := aVar_LightWorking;
  end
else
  begin
    if FileExists(aNameFile.Value , '') then
      begin
        TextFileOpen(aNameFile.AsStr, '', fomAppend, fcpDefault);
        TextFileWriteLn(s);
        TextFileClose;
      end;
    AddMessage(Now, mkMessage, 'Нет переменной LightWorking', True, False);
    Button430.Variable := Nil;
  end;
Все нужные переменные описаны, все нужные каталоги (User files) где нужно созданы (например APath из команды TextFileOpen согласно справке).
Далее было несколько вариантов действий:
1. Строка s просто набор символов (без символьных констант): 'Нет сигнала'
2. Строка s просто набор символов (без символьных констант) + текущее время: DateTimeToStr(Now) + 'Нет сигнала'
3. Далее команда открыть TextFileOpen с различными кодировками (fcpDefault, fcpUTF8, fcpCyrillic_windows1251, fcpEstonian_iso8859_13)
4. Преобразование строки s (UTF8Encode, UTF8ToString, String, без преобразования)
Результат следующий:
1. Преобразование срабатывает с командой String, но не на fcpEstonian_iso8859_13. Понятно почему.
2. Преобразование срабатывает с командой UTF8Encode при fcpUTF8, но не сразу это получилось.
Вопросы.
1. Перед записыванием строки s в файл ее нужно сначала сформировать, преобразовать и потом только вставить?
2. Есть ли ограничения для команды TextFileWriteLn внутри скобок.
Жду ответов и вопросов.


Серега

  • Старожил
  • ****
  • Сообщений: 287
    • Просмотр профиля
Re: Кодировка русского языка при записи в файл
« Ответ #1 : 15 Сентября 2020, 14:46:31 »
В дополнение к первому сообщению.
Если строку s разбить на две части
Код
ss := 'Нет ';
s := DateTimeToStr(Now) + ss + 'сигнала';
то на выходе получим вот это:
15.09.2020  14:37:13 краказябры сигнала !

(краказыбры = 3 знака вопроса, каждый в черном ромбе, https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%BC%D0%B5%D0%BD%D1%8F%D1%8E%D1%89%D0%B8%D0%B9_%D1%81%D0%B8%D0%BC%D0%B2%D0%BE%D0%BB)

Подскажите алгоритм действий как правильно собрать строку и записать ее в файл?

Simple-Scada

  • Администратор
  • *****
  • Сообщений: 3215
    • Просмотр профиля
    • Simple-Scada
Re: Кодировка русского языка при записи в файл
« Ответ #2 : 16 Сентября 2020, 10:46:00 »
Здравствуйте.

Для строк нужно соблюдать только одно правило: не складывать строки с разными кодировками. Иначе часть строки будет испорчена, что логично, ведь нельзя создать строку из двух разных кодировок и при этом правильно отображать её на экране. Кодировки ведь разные. Поэтому часть текста (в правильной кодировке будет отображаться правильно), а другая часть как "случайные" символы. Все примеры которые Вы описали соответствуют вышеописанному правилу. Когда Вы складывали строки в разных кодировках - получался неправильный результат. Когда в одинаковых - правильный.

Все строки, которые в коде заключены в кавычки всегда имеют тип string.
Код: (delphi)
var
  S1: string;
  S2: UTF8String;
begin
  S1 := 'этот текст имеет тип string!';
  S2 := 'этот текст тоже имеет тип string!';
end.

Если нужно чтобы строка в кавычках имела тип UTF8String, то нужно преобразовать её с помощью UTF8Encode:
Код: (delphi)
var
  S1: string;
  S2: UTF8String;
begin
  S1 := UTF8Encode('мой текст');  // в S1 запишется текст в кодировке UTF8String
  S2 := UTF8Encode('мой текст');  // в S2 тоже запишется текст в кодировке UTF8String
end.

И наоборот, если текст имеет тип UTF8String, то его можно привести к string через UTF8ToString. Вот и всё. Далее нужно только не смешивать разные типы строк и преобразовывать все части строки к нужному типу. Можно рассмотреть часть кода из примера который Вы привели. Только Вы не описали переменные s и ss, непонятно какие типы данных они имеют. Наверно string? Тогда получаем следующий код:
Код: (delphi)
var
  s, ss: string;
begin
  ss := 'Нет ';  // здесь всё правильно, в переменную ss типа string записывается строка типа string
  s := DateTimeToStr(Now) + ss + 'сигнала';  // а здесь всё смешивается: string := UTF8String + string + string
end.
Открываем руководство и смотрим функцию DateTimeToStr, она возвращает строку в кодировке UTF8String. Получается, что Вы пытаетесь записать в переменную s типа string строку в которой часть текста в UTF8String, а остальная часть в string. Такую строку никак не получится отобразить в нормальном виде. Если нужно записать строку в переменную типа string, то нужно было все её части перевести в string:
Код: (delphi)
var
  s, ss: string;
begin
  ss := 'Нет ';  // здесь всё правильно, в переменную ss типа string записывается строка типа string
  s := UTF8ToString(DateTimeToStr(Now)) + ss + 'сигнала';  // теперь всё правильно: string := string + string + string
end.

Если в коде разные типы не будут смешиваться, то не возникнет никаких проблем после записи в файл. Неважно даже какие переменные (string или UTF8String) Вы будете записывать в файл, главное не смешивайте разные типы в одной строке.
« Изменён: 16 Сентября 2020, 10:48:41 от Simple-Scada »