Модератор: Модераторы
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.pp
WINEDEBUG=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
Сейчас этот форум просматривают: Google [Bot], Yandex [Bot] и гости: 3