Ещё раз о кодировках

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Ещё раз о кодировках

Сообщение ChimMAG » 24.12.2015 15:04:23

FreePascal 3.0.0. Вот простейшая проверка вывода строки/символа:
Код: Выделить всё
uses crt;
var a:string;
  c:char;
begin
a:='Проверка';
c:='ш';
writeln(a);
writeln(c);
end.

И получаем иероглифы.
Убираем модуль crt - всё отображается нормально.
Такая конструкция:
Код: Выделить всё
{$codepage CP866}
uses crt,windows;
type
  CPString = type AnsiString(866);
var a:CPString;
  b:String

Отображает правильно переменную a, но не b или константы. При этом от значение AnsiString (хоть 866, хоть 1251) ничего не зависит. Использование SetConsoleOutputCP(866); (в модуле Windows) тоже ничего не даёт. Как и использование DefaultSystemCodePage.
Вообще проблема кроется в том, что консоль (и, соотвественно, редактор и кодировка констант в нём) использует кодировку 866, но при выводе идёт конвертирование в кодировку 1251. Причём это поведение изменяется при подключении модуля crt. Без него всё отображается "как есть". Есть способы обойти такую конвертацию?
ChimMAG
незнакомец
 
Сообщения: 3
Зарегистрирован: 24.12.2015 12:20:47

Re: Ещё раз о кодировках

Сообщение zub » 24.12.2015 17:55:58

Исходники в 866? тогда {$codepage CP866} обязательно надо.
crt настраивает консоль на 1251, ее нужно сменить обратно
Код: Выделить всё
TextRec(output).CodePage:=866;

насчет char он разве хранит кодировку символа и умеет перекодировать налету?
в таком виде у меня всё ок
Код: Выделить всё
program Project1;
{$codepage CP866}
uses crt;
var a:String;
  c:char;
begin
a:='Проверка';
c:='ш';
writeln(TextRec(output).CodePage);
TextRec(output).CodePage:=866;
writeln(a);
writeln(c);
readln;
end.   

если исходник сохранен в 866
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: Ещё раз о кодировках

Сообщение ChimMAG » 25.12.2015 08:50:09

Да, исходник в 866 кодировке. Результатом программы является:
    1251
    Џа®ўҐаЄ
    и
Самое интересное оказывается другое. Проверял на другом компьютере, на нём стоит так же Win7 x64 (только ультима, а не про), FreePascal 2.6.4 (но он же на этой машине работает точно так же, как и 3.0.0). Так вот на неё нет абсолютно проблем с кодировкой. Вообще. То есть самая первая программа выдаёт то, что и должно. От чего это может зависить?
ChimMAG
незнакомец
 
Сообщения: 3
Зарегистрирован: 24.12.2015 12:20:47

Re: Ещё раз о кодировках

Сообщение SSerge » 25.12.2015 09:03:56

ChimMAG писал(а):FreePascal 2.6.4


Ничего, что у этого компилятора во внутренней структуре строк не предусмотрено поле для указания кодировки?

Официальную мурзилку читали о том, как именно работать со строками с указанием кодовой страницы? http://wiki.freepascal.org/FPC_Unicode_support/ru
SSerge
энтузиаст
 
Сообщения: 971
Зарегистрирован: 12.01.2012 05:34:14
Откуда: Барнаул

Re: Ещё раз о кодировках

Сообщение ChimMAG » 25.12.2015 09:30:35

Наполовину разобрался. Оказывается имеет значение с помощью чего я запускаю.
2.6.4 Запускаю из-под FAR'а - наблюдаю проблемы с кодировкой. Запускаю в отдельном окне (через проводник или "start") - всё отлично! Проблем нет от слова вообще.
3.0.0 Всегда запускаю в отдельном окне - проблемы что описал выше. Побороть не удаётся.

Добавлено спустя 16 минут 34 секунды:
Да, официальную мурзилку читал, само собой. И шустрил инет на этот предмет. Смущало то, что 2.6.4 показывал похожее поведение, но, оказывается, разница была в том, что его как старую версия, оставленную лишь для тестов, я запускал непосредственно из FAR'а, а 3.0.0. настроил на запуск в отдельном окне. Не предполагал, что в этом проблема может быть. Сейчас третья версия выводит русские буквы при использовании "type AnsiString". Со строковыми константами пока не получается (решение с $CODEPAGE у меня не работает).
ChimMAG
незнакомец
 
Сообщения: 3
Зарегистрирован: 24.12.2015 12:20:47

Re: Ещё раз о кодировках

Сообщение *Rik* » 18.01.2016 12:35:59

Будьте добры, объясните мне дураку, чета я не въезжаю. Поставил Lazarus 1.6RC2 с FPC 3.0 у меня не работают SysToUTF8 и UTF8ToSys.
Сам Lazarus видимо собран с поддержкой UTF8_RTL, т.к. при обращении к SysToUTF8 выполняется самая первая строка Result := S;
Код: Выделить всё
function SysToUTF8(const s: string): string;
begin
  {$IFDEF UTF8_RTL}
  Result:=s;
  {$ELSE}
  if NeedRTLAnsi and (not IsASCII(s)) then
  begin
    Result:=AnsiToUTF8(s);
    {$ifdef FPC_HAS_CPSTRING}
    // prevent UTF8 codepage appear in the strings - we don't need codepage
    // conversion magic in LCL code
    SetCodePage(RawByteString(Result), StringCodePage(s), False);
    {$endif}
  end
  else
    Result:=s;
  {$ENDIF}
end; 


Пытаюсь выполнить простой пример:
Код: Выделить всё
procedure TForm1.Button1Click(Sender: TObject);
var
  S: string;
  SS: String;
begin
  S := GetUserDir;
  ss := SysToUTF8(S);
  ShowMessage(ss);
end; 

GetUserDir возвращает результат в cp1251 (WIn7) ни как не могу переделать результат в UTF8 (работает только LConvEncoding.cp1251ToUTF8()). Как переделать его в UTF8 используя новые возможности FPC 3?

Или оно ещё не работает?
Аватара пользователя
*Rik*
постоялец
 
Сообщения: 427
Зарегистрирован: 19.04.2011 12:18:51
Откуда: Урал

Re: Ещё раз о кодировках

Сообщение SSerge » 18.01.2016 12:57:13

*Rik* писал(а):Как переделать его в UTF8 используя новые возможности FPC 3?

Или оно ещё не работает?


Поставить директиву {$codepage UTF8}, например.
Иначе компилятор ничего не знает о кодовой странице ваших строк.
И если посмотрите текст RTL, большинство функций все знает о типе UnicodeString и работает с ним, а Utf8String - ни одна. Это как бы намёк.

Теория (и часть практики) вот тут: http://wiki.freepascal.org/Better_Unico ... Lazarus/ru

SysToUtf8 и обратно не работают, да. Ибо нет смысла конвертить из utf8 в utf8. О чем в мурзилке написано.
SSerge
энтузиаст
 
Сообщения: 971
Зарегистрирован: 12.01.2012 05:34:14
Откуда: Барнаул

Re: Ещё раз о кодировках

Сообщение *Rik* » 18.01.2016 13:27:54

SSerge писал(а):
*Rik* писал(а):Как переделать его в UTF8 используя новые возможности FPC 3?

Или оно ещё не работает?


Поставить директиву {$codepage UTF8}, например.
Иначе компилятор ничего не знает о кодовой странице ваших строк.
И если посмотрите текст RTL, большинство функций все знает о типе UnicodeString и работает с ним, а Utf8String - ни одна. Это как бы намёк.

Теория (и часть практики) вот тут: http://wiki.freepascal.org/Better_Unico ... Lazarus/ru

SysToUtf8 и обратно не работают, да. Ибо нет смысла конвертить из utf8 в utf8. О чем в мурзилке написано.

Мурзилка прочитана и проэксперементирована по разному и пока безрезультатно...
{$codepage UTF8} прописано.
Полный код модуля (может я не туда директиву прописываю?):
Код: Выделить всё
unit main;

{$mode objfpc}{$H+}
{$codepage UTF8}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
var
  S: string;
begin
  S := GetUserDir;
  ShowMessage(S);
end;

end.

Само оно в этом коде не преобразуется, GetUserDir возвращает cp1251, если имеются русские буквы, там крокозяблы...
Аватара пользователя
*Rik*
постоялец
 
Сообщения: 427
Зарегистрирован: 19.04.2011 12:18:51
Откуда: Урал

Re: Ещё раз о кодировках

Сообщение SSerge » 18.01.2016 13:29:26

Код: Выделить всё
  S := GetUserDir;
  ShowMessage(Format('%d',[StringCodePage(s)]));


Маркировка-то кодовой страницы на строке s стоит 65001 (utf8) :D (CodeTyphon 5.60)
(стандартный текст, без каких либо директив)

вот это:

Код: Выделить всё
procedure TForm1.Button2Click(Sender: TObject);
var
  S: Unicodestring;
  SS: UnicodeString;
begin
  S := GetCurrentDir;
  ShowMessage(Format('%d',[StringCodePage(s)]));
  ss := s;
  ShowMessage(Format('%d',[StringCodePage(ss)]));
  ShowMessage(ss);
end;



работает и отображает название каталога правильно.
Функцию я заменил, пардонъ, у меня нет пользователей с русскими путями

Добавлено спустя 1 минуту 21 секунду:
можно, кста, менять строковые типы, и на всех срабатывает правильно.
Версия компилятора, правда 3.1.1
SSerge
энтузиаст
 
Сообщения: 971
Зарегистрирован: 12.01.2012 05:34:14
Откуда: Барнаул

Re: Ещё раз о кодировках

Сообщение *Rik* » 18.01.2016 13:44:49

SSerge писал(а):
Код: Выделить всё
  S := GetUserDir;
  ShowMessage(Format('%d',[StringCodePage(s)]));


Маркировка-то кодовой страницы на строке s стоит 65001 (utf8) :D (CodeTyphon 5.60)
(стандартный текст, без каких либо директив)

вот это:

Код: Выделить всё
procedure TForm1.Button2Click(Sender: TObject);
var
  S: Unicodestring;
  SS: UnicodeString;
begin
  S := GetCurrentDir;
  ShowMessage(Format('%d',[StringCodePage(s)]));
  ss := s;
  ShowMessage(Format('%d',[StringCodePage(ss)]));
  ShowMessage(ss);
end;



работает и отображает название каталога правильно.
Функцию я заменил, пардонъ, у меня нет пользователей с русскими путями

Добавлено спустя 1 минуту 21 секунду:
можно, кста, менять строковые типы, и на всех срабатывает правильно.
Версия компилятора, правда 3.1.1


У меня Lazarus 1.6RC2 от официальных разработчиков.
Что бы я не делал, код ниже:
Код: Выделить всё
  S := GetUserDir;
  ShowMessage(Format('%d',[StringCodePage(s)]));

Тоже возвращает 65001, но без WinCPToUTF8 там крокозяблы.

Ладно, пока UTF8ToSys и SysToUTF8 заменю на UTF8ToWinCP и WinCPToUTF8, они вроде работают.
Аватара пользователя
*Rik*
постоялец
 
Сообщения: 427
Зарегистрирован: 19.04.2011 12:18:51
Откуда: Урал

Re: Ещё раз о кодировках

Сообщение Cheb » 18.01.2016 16:22:16

{$codepage UTF8} говорит компилятору о кодировке *исходника*, т.е. влияет на что-либо только если у вас есть объявления русских строк в тексте программы.

Для активации юникодных строк в 3.х надо {$modeswitch unicodestrings}
Аватара пользователя
Cheb
энтузиаст
 
Сообщения: 994
Зарегистрирован: 06.06.2005 15:54:34

Re: Ещё раз о кодировках

Сообщение SSerge » 18.01.2016 16:26:39

Cheb писал(а):Для активации юникодных строк в 3.х надо {$modeswitch unicodestrings}


эта директива не для "активации юникодных строк", а для того, чтобы тип string приравнять к unicodestring;
Напрямую указанные переменные типа UnicodeString прекрасно работоспособны и без этого.
SSerge
энтузиаст
 
Сообщения: 971
Зарегистрирован: 12.01.2012 05:34:14
Откуда: Барнаул

Re: Ещё раз о кодировках

Сообщение *Rik* » 18.01.2016 19:56:09

В общем, все эти строки работают, неявное преобразование типов строк происходит, файлы создаются, списки сохраняются без явной конвертации из UTF в Ansi и обратно, мне просто не повезло, я неудачную функцию выбрал для экспериментов, видимо GetUserDir имеет какой-то косяк, т.к. кроме неё пока вроде все остальное работает...
Аватара пользователя
*Rik*
постоялец
 
Сообщения: 427
Зарегистрирован: 19.04.2011 12:18:51
Откуда: Урал

Re: Ещё раз о кодировках

Сообщение AlexEr81 » 17.03.2016 16:30:37

поделюсь своим "открытием": есть проект (показывает данные из сертификата ЭП/запроса/СОС) там в нём было много AnsiToUTF8 т.к. данные извлекались с помощью cryptapi. было все ок на версии laz1.4.
поставил Lazarus 1.6 c FreePascal 3.0.0. получил геморрой - половина данных нормально выводилась половина ??????????????? или вообще пусто там где должен быть текст.после дня подбора функции для нормального вывода текста, чтения форумов и "мурзилок" нашёл простое решение:
все функции/процедуры для извлечения данных у меня были в отдельном модуле(назв. - x509) и там я прописал: {$codepage cp1251}.
в модуле который выводил текст на форму убрались все AnsiToUTF8, от чего код стал намного лучше смотреться.
текст выводится как надо.
p.s.
в x509 если есть текст(константы) то вместо него выводится "???????????" (хотя и не всегда)поэтому для таких случаев использовал WinCpToUTF8
AlexEr81
новенький
 
Сообщения: 17
Зарегистрирован: 24.01.2014 19:57:31


Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 14

Рейтинг@Mail.ru
cron