Модератор: Модераторы
To declare a variable as a string, use the following type specification:
- Код: Выделить всё
... : type string ( unsigned integer )
... : type AnsiString ( unsigned integer )
If there is a codepage specifier, (using round brackets) it indicates an ansistring with associated code page information.
Since strings have code page information associated with them, it is important to know which code page a string uses:
Short strings always use the system code page.
Plain ansistrings use the system code page.
Single byte strings with declared code page use that code page.
The RawBytestring type has no code page information associated with it.
Constant strings have the code page of the source file. If none is specified the system codepage is used (CP_ACP).
See Programmer’s Guide, {$CODEPAGE } directive.
Сквозняк писал(а):A5:=A5+#171; перекодируется и длина A5 получается больше 1

interface
TYPE
{$IFDEF WINDOWS}
STROKI1 = RAWBYTESTRING;
UU5,a5: RAWBYTESTRING;
O5: STROKI1;
writeln('____a5____',stringcodepage(a5));
a5:='';
a5:=#171;
writeln('a5 ',length(a5),' ',ord(a5[1]));
if length(a5)>1 then writeln(ord(a5[1]));
writeln('____a5-2____');
O5:='';
O5:=O5+#171;
WRITELN('____________0----738_O5 ',LENGTH(O5),' ',STRINGCODEPAGE(O5));
IF LENGTH(O5)>1 THEN WRITELN('____________0----738_O5-2 ',ORD(O5[1]),' ',ORD(O5[2]));
writeln('____0_0____');
a5:='';
a5:=#171;
writeln('a5 ',length(a5),' ',ord(a5[1]));
if length(a5)>1 then writeln(ord(a5[1]));
writeln('____0____',stringcodepage(a5));
a5:='';
a5:=#171;
writeln('a5 ',length(a5),' ',ord(a5[1]));
if length(a5)>1 then writeln(ord(a5[1]));
writeln('____0_ ___');
writeln('____1____',stringcodepage(O5));
O5:='';
O5:=#171;
writeln('O5 ',length(O5),' ',ord(O5[1]));
if length(O5)>1 then writeln(ord(O5[1]));
writeln('____1_ ___');
____a5____65001
a5 1 171
____a5-2____
____________0----738_O5 2 65001
____________0----738_O5-2 208 187
____0_0____
a5 1 171
____0____866
a5 1 171
____0_ ___
____1____65001
O5 1 171
____1_ ___
writeln('____a5-2____');
         O5:='';
         O5:=O5+chr(171); //#171;
         WRITELN('____________0----738_O5 ',LENGTH(O5),' ',STRINGCODEPAGE(O5));
  IF LENGTH(O5)>1 THEN WRITELN('____________0----738_O5-2 ',ORD(O5[1]),' ',ORD(O5[2]));
____a5-2____
____________0----738_O5 2 65001
____________0----738_O5-2 208 187
 Плохо, что нужно искать, где в компиляторе это автоматическое перекодирование прописано, а потом патчить и пересобирать компиляторы вместе с лазарусами - звиздец, сколько работы бракоделы устроили.
 Плохо, что нужно искать, где в компиляторе это автоматическое перекодирование прописано, а потом патчить и пересобирать компиляторы вместе с лазарусами - звиздец, сколько работы бракоделы устроили.C:lazarus-2.0.10-fpc-3.2.0-win64fpc3.2.0binx86_64-win64fpc.exe -FuC:lazarus-2.0.10-fpc-3.2.0-win64lclunitsx86_64-win64win32 -FuC:lazarus-2.0.10-fpc-3.2.0-win64lclunitsx86_64-win64 -FuC:lazarus-2.0.10-fpc-3.2.0-win64componentslazutilslibx86_64-win64 -FuC:lazarus-2.0.10-fpc-3.2.0-win64packagerunitsx86_64-win64 -dLCL -dLCLwin32 -Twin64 -Xm -WN -XX -CX 1.ppWINEDEBUG=fixme-all,err-all wine cmd.exe{$codepage CP866}
uses
WINDOWS, SYSUTILS;
type
//RawByteString2 = type AnsiString(CP_NONE); //С ЭТОЙ СТРОКОЙ ТОЖЕ САМОЕ
RawByteString2 = type RawByteString;
VAR
Q3: BYTE;
A5: RAWBYTESTRING;
B5: RawByteString2;
Q2,W2,E2: LONGINT;
 
BEGIN
Q2:=StringCodePage(B5);
WRITELN('____Q2=',Q2);
Q3:=138;
A5:=CHR(Q3);
WRITELN(LENGTH(A5));
setconsolecp(866);
A5:=A5+#171;
B5:='';
B5:=B5+#171;
WRITELN(LENGTH(A5),'  ',LENGTH(B5),'  ',CP_NONE,' ',StringCodePage(A5),' ',StringCodePage(B5)); // ... 65535
FOR W2:=1 TO 500 DO BEGIN
   E2:=StringCodePage(B5);
   B5:=#171;
   IF E2<>Q2 THEN WRITELN(length(B5),' !!!!!!1!____E2=',E2,'   W2=',W2);
   Q2:=E2;   
   setconsolecp(866);
   E2:=StringCodePage(B5);
   B5:=#171;
   IF E2<>Q2 THEN WRITELN(length(B5),' !!!!!!2!____E2=',E2,'   W2=',W2);
   Q2:=E2;
   SLEEP(2);
                    END;
WRITELN('________________________ ',length(B5));
END.
____Q2=1251
1
2  1  65535 1251 1251
1 !!!!!!2!____E2=866   W2=1
________________________ 1
setconsolecp(866);
zub писал(а): и только помогает верно перекодировать захардкоженые строки в DefaultSystemCodePage
zub писал(а):Без обид, но демка альтернативно одаренная, сделай по человечески

Снег Север писал(а):Чтобы не перекодировалось используют TByteArray.
Type
TByteArray = Array of Byte;program Project1;
{$Codepage cp866}
var
  rusAcode866:byte;
begin
  rusAcode866:=128;
  writeln('',' CP=',StringCodePage(''));//DefaultUnicodeCodePage потому что строки нет
  writeln(chr(rusAcode866),' CP=',StringCodePage(chr(rusAcode866)));//DefaultUnicodeCodePage потому что строка создана в рантайме как результат вызова функции
  writeln(chr(128),' CP=',StringCodePage(chr(128)));//cp866 потому что строка создана в компайлтайме из символа и указано что исходник "какбудто" в 866
  writeln(#128,' CP=',StringCodePage(#128));//cp866 потому что строка создана в компайлтайме из символа и указано что исходник "какбудто" в 866
  readln;
end. Сквозняк писал(а):Но это же вообще не строки!

zub писал(а):Все работает как надо.
zub писал(а):Серьезно? ты умудряешся из паскаля помойку восклицательных знаков, прочерков и "значащих" имен переменных сделать))
{$codepage CP866}
USES
SYSUTILS, WINDOWS;
TYPE
STROKI1 = type AnsiString(866);
STROKI2 = type AnsiString;
VAR
Q5: STROKI1;
A5,S5: STROKI2;
Z5: array of AnsiString;
Info: TSearchRec;
Q2,W2: LONGINT;
BEGIN
W2:=DEFAULTSYSTEMCODEPAGE;
WRITELN('______DEFAULTSYSTEMCODEPAGE=',DEFAULTSYSTEMCODEPAGE);
SetMultiByteConversionCodePage(866);
SETLENGTH(Z5,2);
Z5[0]:='/c'; 
Z5[1]:='chcp 866';
SysUtils.ExecuteProcess('cmd.exe',Z5,1);
setconsolecp(866);
WRITELN('__Q5__ ',StringCodePage(Q5));
WRITELN('__A5__ ',StringCodePage(A5));
Q5:=#171;
A5:=#171;
WRITELN('__Q5__ ',StringCodePage(Q5),' ',LENGTH(Q5),' ',ORD(Q5[1]));
WRITELN('__A5__ ',StringCodePage(A5),' ',LENGTH(A5),' ',ORD(A5[1]));
A5:='GF*'; //НАЧАЛО ИМЕНИ КАТАЛОГА, ДРУГАЯ ЧАСТЬ СОДЕРЖИТ ПРОБЕЛ И НЕЛАТИНСКИЕ СИМВОЛЫ
S5:='SLUCILASJ LAZA';
Q2:=SYSUTILS.findfirst(A5,faDirectory+faAnyFile+fahidden+fareadonly,Info);
IF Q2=0 THEN S5:=INFO.NAME;
SYSUTILS.FINDCLOSE(Info);
WRITELN('__INFO.NAME__ ',StringCodePage(S5),' ',LENGTH(S5),' ',S5);
A5:=S5+'1*'; //ИЩЕМ ФАЙЛ В КАТАЛОГЕ
S5:='SLUCILASJ LAZA';
Q2:=SYSUTILS.findfirst(A5,faDirectory+faAnyFile+fahidden+fareadonly,Info);
IF Q2=0 THEN S5:=INFO.NAME;
SYSUTILS.FINDCLOSE(Info);
WRITELN('__INFO.NAME__ ',StringCodePage(S5),' ',LENGTH(S5),' ',S5);
END.повторяю, кодировка исходника и $CODEPAGE это разные вещи и работают только на стадии компиляции для захардкоженых строк
чтобы понять откуда вылезла 1251 - смотрим внутрь StringCodePage и внимательно вдумываемся что там происходит когда на входе пустая строка (nil)
{$define FPC_HAS_ANSISTR_CONCAT}
procedure fpc_AnsiStr_Concat (var DestS:RawByteString;const S1,S2 : RawByteString{$ifdef FPC_HAS_CPSTRING};cp : TSystemCodePage{$endif FPC_HAS_CPSTRING}); compilerproc;
Var
  S1Len, S2Len: SizeInt;
  same : boolean;
  S1CP, S2CP, DestCP: TSystemCodePage;
begin
{$ifdef FPC_HAS_CPSTRING}
  DestCP:=cp;
  if DestCp=CP_NONE then
    DestCP:=DefaultSystemCodePage;
{$else FPC_HAS_CPSTRING}
  DestCP:=StringCodePage(DestS);
{$endif FPC_HAS_CPSTRING}
  DestCP:=TranslatePlaceholderCP(DestCP);
  { if codepages are different then concat using unicodestring,
    but avoid conversions if either addend is empty (StringCodePage will return
    DefaultSystemCodePage in that case, which may differ from other addend/dest) }
  if S1='' then
    S1CP:=DestCP
  else
    S1CP:=StringCodePage(S1);
  S1CP:=TranslatePlaceholderCP(S1CP);
  if S2='' then
    S2CP:=DestCP
  else
    S2CP:=StringCodePage(S2);
  S2CP:=TranslatePlaceholderCP(S2CP);
{$ifdef FPC_HAS_CPSTRING}
  { if the result is rawbytestring and both strings have the same code page,
    keep that code page }
  if (cp=CP_NONE) and
     (S1CP=S2CP) then
    DestCP:=S1CP;
{$endif FPC_HAS_CPSTRING}
  if (S1CP<>DestCP) or (S2CP<>DestCP) then
    begin
      ansistr_concat_complex(DestS,S1,S2,DestCP);
      exit;
    end;
  { only assign if s1 or s2 is empty }
  if (S1='') then
    begin
      DestS:=s2;
      exit;
    end;
  if (S2='') then
    begin
      DestS:=s1;
      exit;
    end;
  S1Len:=Length(S1);
  S2Len:=length(S2);
  { Use Pointer() typecasts to prevent extra conversion code }
  if Pointer(DestS)=Pointer(S1) then
    begin
      same:=Pointer(S1)=Pointer(S2);
      SetLength(DestS,S1Len+S2Len);
      if same then
        fpc_pchar_ansistr_intern_charmove(PAnsiChar(DestS),0,DestS,S1Len,S2Len)
      else
        fpc_pchar_ansistr_intern_charmove(PAnsiChar(S2),0,DestS,S1Len,S2Len+1)
    end
  else if Pointer(DestS)=Pointer(S2) then
    begin
      SetLength(DestS,S1Len+S2Len);
      fpc_pchar_ansistr_intern_charmove(PAnsiChar(DestS),0,DestS,S1Len,S2Len+1);
      fpc_pchar_ansistr_intern_charmove(PAnsiChar(S1),0,DestS,0,S1Len);
    end
  else
    begin
      SetLength(DestS,S1Len+S2Len);
      fpc_pchar_ansistr_intern_charmove(PAnsiChar(S1),0,DestS,0,S1Len);
      fpc_pchar_ansistr_intern_charmove(PAnsiChar(S2),0,DestS,S1Len,S2Len+1);
    end;
  SetCodePage(DestS,DestCP,false);
end;
{$endif FPC_HAS_ANSISTR_CONCAT}смысл не держать все строки в какойто кодировке а дать компилятору возможность правильно определить их начальную кодировку и в дальнейшем перекодировать их в требуемую
Снег Север писал(а):Я вас удивлю, но строки - это и есть массивы байтов, только со специальной обработкой и, возможно, дополнительными полями (короткие строки так на 100% байты). поэтому, если вы хотите получить необработанный набор байтов от источника, то получайте и храните именно как набор байтов, а потом уже конвертируйте в свои строки с нужной вам кодировкой. В делфи это делается через функции класса TEncoding.
zub писал(а):Компилятор на выходе своих процедур рожает строки с DefaultSystemCodePage - так и задумано.
zub писал(а):Все проблемы с кодировками (ну почти все) от того что компилятор не смог определить кодировку захардкоженых строк (програмист приложил к этому руку) и дальше все ломается
Вернуться в Free Pascal Compiler
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1