Autor Téma: zápolení s přechodem na Unicode  (Přečteno 278 krát)

Offline Morrison

  • Hrdina
  • ****
  • Příspěvků: 291
  • Karma: 12
    • Verze Delphi: D5, XE2, 10.4
zápolení s přechodem na Unicode
« kdy: 19-07-2020, 10:30:45 »
Poprvé v životě převádím appku z Ansi na Unicode, a evidentně občas narazím na nějaké zákysy, takže je budu soustředit do tohoto vlákna.
Aktuálně řeším toto:

Ord(Char(#130)) = 8218

Dává vám to nějaký smysl? Jak se Delphi dopracovalo k 8218?
« Poslední změna: 19-07-2020, 10:34:30 od Morrison »
nil

Offline Radek Červinka

  • Administrátoři
  • Padawan
  • *****
  • Příspěvků: 2666
  • Karma: 104
    • Verze Delphi: D2007, DXE + 2 poslední
    • O Delphi v češtině
Re:zápolení s přechodem na Unicode
« Odpověď #1 kdy: 19-07-2020, 10:58:56 »
Ano, znaky nad 127 jsou národní znaky (proste pokud je nastaven nejvyssi bit, neni to ASCII), tj. Char(#130) provedlo konverzi na unicode Char (tj. 16 bit) z aktualni znakove stranky, kde znak #130 byl nejak reprezentovan a byl preveden na odpovidajici znak v unicode
Embarcadero MVP - Czech republic

Offline Morrison

  • Hrdina
  • ****
  • Příspěvků: 291
  • Karma: 12
    • Verze Delphi: D5, XE2, 10.4
Re:zápolení s přechodem na Unicode
« Odpověď #2 kdy: 19-07-2020, 11:09:23 »
Díky za vysvětlení. Takže zpátky k těm 130 se dostanu převodem zpět na Ansi

Ord(AnsiChar(#130)) = 130

Jen abych vysvětlil, proč a k čemu...máme upravený TabListBox, kde se do Items vkládají kromě textu navíc ještě formátovací značky, se kterými se pak pracuje při vykreslování. Těhle 130 je například hodnota za značkou Odsazení.
nil

Offline Radek Červinka

  • Administrátoři
  • Padawan
  • *****
  • Příspěvků: 2666
  • Karma: 104
    • Verze Delphi: D2007, DXE + 2 poslední
    • O Delphi v češtině
Re:zápolení s přechodem na Unicode
« Odpověď #3 kdy: 19-07-2020, 11:19:07 »
8218 = $0201A = počáteční úvozovka jednoduchá
což je ekvivalent #130 ale ne pro unicode - zrovna toto bude asi nejaka vyjimka, protoze kdyby jsi tam napsal IntToStr(Ord('‚')) tak to projde bez problemu,
takto to kompilator asi jeste konvertuje nez provede generovani kodu

Embarcadero MVP - Czech republic

Offline Morrison

  • Hrdina
  • ****
  • Příspěvků: 291
  • Karma: 12
    • Verze Delphi: D5, XE2, 10.4
Re:zápolení s přechodem na Unicode
« Odpověď #4 kdy: 19-07-2020, 11:28:39 »
No jo, opravdu se to chová nepředvídatelně.

Ord(AnsiChar(#130)) = 130

ale jakmile to dám do stringu, už to vrací něco jiného:

Kód: Delphi [Vybrat]
  1. var
  2.   S: String;
  3.   Odsazeni: Integer;
  4.  
  5. S := 'Text1' + #130 + 'Text2';
  6. Odsazeni := Ord(S[6]); // <- 8218
  7. Odsazeni := Ord(AnsiChar(S[6])); // <- 26
  8. Odsazeni := Ord(AnsiString(S)[6]); // <- 130
  9.  
nil

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 2842
  • Karma: 135
    • Verze Delphi: D2007, XE3, DX10
Re:zápolení s přechodem na Unicode
« Odpověď #5 kdy: 19-07-2020, 13:23:45 »
Jen abych vysvětlil, proč a k čemu...máme upravený TabListBox, kde se do Items vkládají kromě textu navíc ještě formátovací značky, se kterými se pak pracuje při vykreslování. Těhle 130 je například hodnota za značkou Odsazení.
No a neni mozne ty vase znacky namapovat na strandardni ridici kody ASCII, ktere nepodlehaji zadne konverzi? Samozrejme si muzes vybrat nejake znacky v unicode, ale to bude vzdycky trpet pri nejakych (implicitnich) konverzich Ansi<->Unicode. Pokud je to slusne napsany, tak prepsat na jedinem miste par znacek je to nejmensi...

Offline Morrison

  • Hrdina
  • ****
  • Příspěvků: 291
  • Karma: 12
    • Verze Delphi: D5, XE2, 10.4
Re:zápolení s přechodem na Unicode
« Odpověď #6 kdy: 19-07-2020, 14:17:45 »
Ty značky samotné nejsou problém, jsou namapované, jak píšeš, na řídící znaky < #10
Jen ta značka odsazení funguje tak, že je ve stringu následována znakem, jehož ordinální hodnota znamená délku odsazení (v pixelech). To je právě v mém příkladu těch #130 a znamená to odsadit následující text o 130 px.

Je to jednoduchý a v Ansi bez problémů funkční systém. Ale asi nebude zbytí a bude se to muset předělat do něčeho civilizovanějšího, třeba HTML

Edit: a nebo spíš půjdu cestou té konverze zpět na AnsiString, tedy jen co se týče těch řídících znaků, zbytek řetězce (resp. jeho kopii) ponechám v Unicode.
« Poslední změna: 19-07-2020, 14:25:48 od Morrison »
nil

Offline JaroB

  • Guru
  • *****
  • Příspěvků: 1002
  • Karma: 28
    • Verze Delphi: XE8, Seattle
Re:zápolení s přechodem na Unicode
« Odpověď #7 kdy: 19-07-2020, 16:44:57 »
Nemusí se dávat 130 binárně, může to být jako číslo, když je to řetězec, ne? co třeba něco jako ^B'130' ?

Používám to podobně a bez problémů, ale je fakt, že je to přes vlastní property kvůli dekódování.

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 2842
  • Karma: 135
    • Verze Delphi: D2007, XE3, DX10
Re:zápolení s přechodem na Unicode
« Odpověď #8 kdy: 19-07-2020, 16:46:23 »
No jo, opravdu se to chová nepředvídatelně.
Ord(AnsiChar(#130)) = 130
No v tom bude hrat roli to, jak prekladac interpretuje tech #130, jak se posilal Igor http://docwiki.embarcadero.com/RADStudio/Sydney/en/HIGHCHARUNICODE_directive_%28Delphi%29. Takze implicitne jako Ansi a pokud ho potrebuje retezit s unicode stringeme, tak vlozi implicitni konverzi Ansi(CP) -> Unicode a totez dela obracene.

Ja bych to zapsal hexadecimalne 4 cislicemi tj. #$0082 (AFAIK tak Delphi neco jako \uXXXX nema), aby z toho rovnou vznikl unicode char a zpatky to cetl pres ord() ev. typecastem word().

Offline JaroB

  • Guru
  • *****
  • Příspěvků: 1002
  • Karma: 28
    • Verze Delphi: XE8, Seattle
Re:zápolení s přechodem na Unicode
« Odpověď #9 kdy: 19-07-2020, 18:25:34 »
nebylo by lepší třeba řešení, viz

Kód: Delphi [Vybrat]
  1. S := 'Text1' + ^B + IntToStr(130) + ^B + 'Text2';
  2. Odsazeni := StrToInt(ExtractWord(S, 2, [^B])); // funkce třeba z RxLib
  3.  

Offline Morrison

  • Hrdina
  • ****
  • Příspěvků: 291
  • Karma: 12
    • Verze Delphi: D5, XE2, 10.4
Re:zápolení s přechodem na Unicode
« Odpověď #10 kdy: 19-07-2020, 22:27:27 »
Co to je za zápis to ^B ? Překladač mi z toho udělá #2, ale je to pro mě novinka, dosud jsem tu stříšku znal jen jako operátor dereference.
Jinak kvůli zpětné kompatibilitě bych to samozřejmě rád řešil pouze na úrovni té komponenty, i když to bude znamenat převody znakových sad, než ve stovce dalších unit, kde se ta komponenta používá. Když ten UnicodeString převedu na AnsiString a vyzobnu z něj jen ten znak na pozici odsazení a na něm si pak udělám Ord(), tak to funguje správně. Otázka samozřejmě je, jak moc se na to dá spolehnout. Ne že by to bylo nějak kritické, v nejhorším případě bude mít uživatel rozhozené zobrazení v nějakém tom našem ListBoxu a to se jistě ozve.
nil

Offline Morrison

  • Hrdina
  • ****
  • Příspěvků: 291
  • Karma: 12
    • Verze Delphi: D5, XE2, 10.4
Re:zápolení s přechodem na Unicode
« Odpověď #11 kdy: 19-07-2020, 22:51:04 »
Protože sám nemám rád nejasně formulované dotazy, tak přikládám hrubý koncept, jak ta komponenta funguje.

někde v aplikaci:
Kód: Delphi [Vybrat]
  1. TabListBox.Items.Add('Název:' + Odrazka + #130 + 'Text ABC'); // odsadit "Text ABC" o 130 px dale
  2.  

TTabListBox:
Kód: Delphi [Vybrat]
  1. const
  2.   Odrazka = #1;
  3.   TTabListBox = class(TListBox)
  4.   ....
  5. procedure TTabListBox.DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState);
  6. var
  7.   Pozice: Integer;
  8.   Odsazeni: Integer;
  9.   S1: String;
  10.   S2: String;
  11. begin
  12.   if Assigned(OnDrawItem) then
  13.     OnDrawItem(Self, Index, Rect, State)
  14.   else
  15.   begin
  16.     S1 := Items[Index];
  17.     repeat
  18.       Pozice := Pos(Odrazka, S1);
  19.       if Pozice > 0 then  {nasel odrazku}
  20.       begin
  21.         S2 := Copy(S1, 1, Pozice - 1);  {retezec pred odrazkou}
  22.         // tady by to melo dat to Odsazeni = 130
  23.         // Odsazeni := Ord(S1[Pozice + 1]);  {delka odsazeni} //tohle fungovalo v Ne-Unicode Delphi
  24.         Odsazeni := Ord(AnsiString(S1)[Pozice + 1]); // takhle to funguje v Unicode Delphi
  25.         S1 := Copy(S1, Pozice + 2, Length(S1));  {zbyly retezec}
  26.       end
  27.       else
  28.       begin
  29.         S2 := S1;
  30.       end;
  31.       Canvas.TextOut(Rect.Left, Rect.Top, S2);
  32.       Rect.Left := Rect.Left + Odsazeni; {nastaveni dalsi pozice}
  33.     until (Pozice = 0);
  34.   end;
  35. end;
  36.  
« Poslední změna: 19-07-2020, 23:01:33 od Morrison »
nil

Offline JaroB

  • Guru
  • *****
  • Příspěvků: 1002
  • Karma: 28
    • Verze Delphi: XE8, Seattle
Re:zápolení s přechodem na Unicode
« Odpověď #12 kdy: 20-07-2020, 07:44:08 »
Excellent
Rated 1 time
Oč je to jiné?

Kód: Delphi [Vybrat]
  1. const
  2.    Odrazka = ^A;
  3.  
  4. TabListBox.Items.Add('Název:' + Odrazka + InToStr(130) + Odrazka + 'Text ABC');
  5.  

Kód: Delphi [Vybrat]
  1. uses
  2.   RxStrUtils;
  3.  
  4.  
  5. procedure TTabListBox.DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState);
  6. var
  7.   Pozice: Integer;
  8.   Odsazeni: Integer;
  9.   S1: String;
  10.   S2: String;
  11. begin
  12.   if Assigned(OnDrawItem) then
  13.     OnDrawItem(Self, Index, Rect, State)
  14.   else
  15.   begin
  16.     S1 := Items[Index];
  17.     repeat
  18.       Pozice := StrToInt(ExtractWord(2, S1, [Odrazka])); // if not TryStrToInt(ExtractWord(2, S1, [Odrazka]), Pozice) then Pozice := 0;
  19.       if Pozice > 0 then  {nasel odrazku}
  20.       begin
  21.         S2 := ExtractWord(1, S1, [Odrazka]);  {retezec pred odrazkou}
  22.         // tady by to melo dat to Odsazeni = 130
  23.         // Odsazeni := Ord(S1[Pozice + 1]);  {delka odsazeni} //tohle fungovalo v Ne-Unicode Delphi
  24.         //Odsazeni := Ord(AnsiString(S1)[Pozice + 1]); // takhle to funguje v Unicode Delphi
  25.         S1 := ExtractWord(3, S1, [Odrazka]);  {zbyly retezec}
  26.       end
  27.       else
  28.       begin
  29.         S2 := ExtractWord(1, S1, [Odrazka]) + ' ' + ExtractWord(3, S1, [Odrazka]);
  30.       end;
  31.       Canvas.TextOut(Rect.Left, Rect.Top, S2);
  32.       Rect.Left := Rect.Left + Odsazeni; {nastaveni dalsi pozice}
  33.     until (Pozice = 0);
  34.   end;
  35. end;
  36.