UTF8 strings and characters/fi

From Free Pascal wiki

English (en) suomi (fi) русский (ru)

UTF-8 merkit ja merkkijonot

UTF-8:n kauneus

Tavut joiden ylin bitti on '0' (0xxxxxxx) on varattu ASCII- yhteensopiville yhden tavun merkille. Monitavuisilla 1: n lukumäärä ensimmäisessä tavussa määrää koodin tavujen tavujen määrän. Esimerkit :

  • 1 tavu : 0xxxxxxx
  • 2 tavua : 110xxxxx 10xxxxxx
  • 3 tavua : 1110xxxx 10xxxxxx 10xxxxxx
  • 4 tavua : 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

Merkistökoodaus UTF-8:n suunnittelussa on joitain etuja verrattuna muihin koodauksiin:

  • Se on taaksepäin yhteensopiva ASCII:n kanssa ja tuottaa pienikokoisia datatiedostoja länsimaisille kielille. ASCII:ta käytetään myös merkintäkielen tunnisteissa ja muissa metatiedoissa, jotka antavat UTF-8: lle etua millä tahansa kielellä.

Kuitenkin tämä taaksepäin yhteensopivuus ei ulotu koodiin, koska koodia on käsiteltävä niin että vältetään utf8-merkkijonoja.

  • Monitavuisen datan eheys voidaan todentaa '1'-bittien määrästä kunkin tavun alussa.
  • Aina löytyy monitavuisen kooditavun alkukohta, vaikka hyppättäisiin satunnaisen tavun paikkaan.
  • Tavu tietyssä paikassa monitavuisessa sekvenssissä ei voi koskaan sekoittaa muiden tavujen kanssa. Tämä sallii perinteisten nopeiden merkkijono funktioiden, kuten Pos () ja Copy (), käytön monissa tilanteissa. Katso esimerkkejä alenpana.

Huomaa, että UTF-16: ssä on samanlaisia ​​eheysominaisuuksia. (D800-alue signaalit ensin korvikkeena, DC00-alue signaalit toissijaisen korvaavan osan)

  • Vakaa koodi. Koodi, joka käsittelee koodipisteitä, on aina tehtävä oikein UTF-8: n kanssa, koska monitavuiset koodipisteet ovat yleisiä. UTF-16: ssä on runsaasti "likaista" koodia, joka olettaa koodipisteiden kiinteän leveyden.
  • Useimmat Internetissä olevat tekstitiedot on koodattu UTF-8: ksi. Tietojen käsittely suoraan UTF-8: ksi eliminoi hyödyttömiä muunnoksia. Useat (Unix-) käyttöjärjestelmät käyttävät UTF-8:aa natiivisti.


Esimerkit

Yksinkertainen iterointi merkkien yli ikään kuin merkkijono olisi joukko yhtä suuria elementtejä ei toimi Unikoodissa. Tämä ei ole pelkästään UTF-8: lle ominaista, Unicode-standardi on monimutkainen ja sana "merkki" on epäselvä. Jos halutaan iteroida UTF-8-merkkijonon merkkejä, on periaatteessa kaksi tapaa:

  • iterointi tavujen yli - hyödyllinen alimerkkijonon etsimiseksi tai kun tarkastellaan vain UTF8-merkkijonon ASCII-merkkejä, esimerkiksi XML-tiedostojen jäsentämisessä.
  • iterointi koodipisteiden tai merkkien yli - hyödyllinen graafisille komponenteille kuten SynEdit, esimerkiksi kun halutaan tietää kolmannen tulostettavan merkin näytöllä.

Alimerkkijonon etsiminen

UTF8: n erityisluonteen vuoksi voit yksinkertaisesti käyttää tavanomaisia ​​merkkijonofunktioita alimerkkijonon etsimiseen. Kelvollisen UTF-8-merkkijonon etsiminen Pos: lla palauttaa aina oikean UTF-8 tavun paikan:


uses LazUTF8;
...
procedure Where(SearchFor, aText: string);
var
  BytePos: LongInt;
  CodepointPos: LongInt;
begin
  BytePos:=Pos(SearchFor,aText);
  CodepointPos:=UTF8Pos(SearchFor,aText);
  writeln('The substring "',SearchFor,'" is in the text "',aText,'"',
    ' at byte position ',BytePos,' and at codepoint position ',CodepointPos);
end;

Etsi ja kopioi

Toinen esimerkki siitä, miten Pos (), Copy () ja Length () toimivat UTF-8: n kanssa. Tällä toiminnolla ei ole koodia käsitellä UTF-8-koodausta, mutta se toimii aina voimassa olevan UTF-8-tekstin kanssa.

function SplitInHalf(Txt, Separator: string; out Half1, Half2: string): Boolean;
var
  i: Integer;
begin
  i := Pos(Separator, Txt);
  Result := i > 0;
  if Result then
  begin
    Half1 := Copy(Txt, 1, i-1);
    Half2 := Copy(Txt, i+Length(Separator), Length(Txt));
  end;
end;

Iterointi merkkijonon yli etsien ASCII merkkejä

Jos halutaan vain etsiä merkkejä ASCII-alueella, voidaan käyttää Char-tyyppiä ja verrata Txt[i] -muotoon aivan kuten aiemmin tehtiin. Useimmat jäsentimet tekevät niin ja ne toimivat yhä.

procedure ParseAscii(Txt: string);
var
  i: Integer;
begin
  for i:=1 to Length(Txt) do
    case Txt[i] of
      '(': PushOpenBracketPos(i);
      ')': HandleBracketText(i);
    end;
end;

Iterointi merkkijonon yli etsien Unikoodi merkkejä tai tekstiä

Jos halutaan löytää merkkijonossa kaikki tietyn merkin tai alimerkkijonon esiintymät niin kutsutaan PosEx()-funktiota toistuvasti.

Jos halutaan testata eri tekstiä silmukan sisällä, voidaan silti käyttää nopeata Copy() ja Length() funktiota. UTF-8-ominaisuuksia voitaisiin käyttää, mutta niitä ei tarvita.

procedure ParseUnicode(Txt: string);
var
  Ch1, Ch2, Ch3: String;
  i: Integer;
begin
  Ch1 := 'Й';  // Characters to search for. They can also
  Ch2 := 'ﯚ';  //  be combined codepoints or longer text.
  Ch3 := 'Å';
  for i:=1 to Length(Txt) do
  begin
    if Copy(Txt, i, Length(Ch1)) = Ch1 then
      DoCh1(...)
    else if Copy(Txt, i, Length(Ch2)) = Ch2 then
      DoCh2(...)
    else if Copy(Txt, i, Length(Ch3)) = Ch3 then
      DoCh3(...)
  end;
end;

Silmukkaa voidaan optimoida hyppäämällä jo käsiteltävien osien päälle.

Merkkijonon yli iterointi analysoimalla yksittäisiä koodipisteitä

Tämä koodi kopioi kunkin koodipisteen String-tyyppiseen muuttujaan, jota voidaan sitten käsitellä edelleen.

procedure IterateUTF8(S: String);
var
  CurP, EndP: PChar;
  Len: Integer;
  ACodePoint: String;
begin
  CurP := PChar(S);        // if S='' then PChar(S) returns a pointer to #0
  EndP := CurP + length(S);
  while CurP < EndP do
  begin
    Len := UTF8CodepointSize(CurP);
    SetLength(ACodePoint, Len);
    Move(CurP^, ACodePoint[1], Len);
    // A single codepoint is copied from the string. Do your thing with it.
    ShowMessageFmt('CodePoint=%s, Len=%d', [ACodePoint, Len]);
    // ...
    inc(CurP, Len);
  end;
end;

Tavujen käyttäminen yhdellä UTF8-koodipisteellä

UTF-8-koodatut koodipisteet voivat vaihdella pituudeltaan, joten paras ratkaisu niiden käyttämiseen on käyttää iteraatiota. Voidaan iteroida koodeja käyttämällä tätä koodia:

uses LazUTF8;
...
procedure DoSomethingWithString(AnUTF8String: string);
var
  p: PChar;
  CPLen: integer;
  FirstByte, SecondByte, ThirdByte, FourthByte: Char;
begin
  p:=PChar(AnUTF8String);
  repeat
    CPLen := UTF8CodepointSize(p);

    // Here you have a pointer to the char and its length
    // You can access the bytes of the UTF-8 Char like this:
    if CPLen >= 1 then FirstByte := P[0];
    if CPLen >= 2 then SecondByte := P[1];
    if CPLen >= 3 then ThirdByte := P[2];
    if CPLen = 4 then FourthByte := P[3];

    inc(p,CPLen);
  until (CPLen=0) or (p^ = #0);
end;

Pääsy N:teen UTF8-koodipisteeseen

Iteraation lisäksi voi olla myös halu päästä satunnaiseen UTF-8-koodipisteeseen.

uses LazUTF8;
...
var
  AnUTF8String, NthCodepoint: string;
begin
  NthCodepoint := UTF8Copy(AnUTF8String, N, 1);

Näytetään koodipisteet UTF8CodepointToUnicode-ohjelmalla

Seuraavassa on esimerkki siitä, miten kunkin koodipisteen 32 bittisen koodipisteen arvo näytetään UTF8-merkkijonona:

uses LazUTF8;
...
procedure IterateUTF8Codepoints(const AnUTF8String: string);
var
  p: PChar;
  unicode: Cardinal;
  CPLen: integer;
begin
  p:=PChar(AnUTF8String);
  repeat
    unicode:=UTF8CodepointToUnicode(p,CPLen);
    writeln('Unicode=',unicode);
    inc(p,CPLen);
  until (CPLen=0) or (unicode=0);
end;

Hajotetut merkit

Unicoden epäselvyyden vuoksi vertailufunktioissa ja Pos() saattaa näkyä odottamatonta käyttäytymistä, kun esimerkiksi yksi merkkijono sisältää hajonneita merkkejä, kun taas toinen käyttää samaan kirjaimeen suoria koodeja. RTL ei käsittele sitä automaattisesti. Se ei ole mikään koodaus, mutta yleensä Unicode.


Mac OS X

FileUtil-yksikön tiedostotoiminnot huolehtivat myös Mac OS X - käyttöjärjestelmäkohtaisesta käyttäytymisestä: OS X normalisoi tiedostonimet. Esimerkiksi filename 'ä.txt' voidaan koodata Unicodessa kahdella eri sekvenssillä (#$C3#$A4 ja 'a'#$CC#$88). Linuxissa ja BSD:ssä voidaan luoda tiedostonimi molemmilla koodauksilla. OS X muuntaa automaattisesti umlaut kolmelle tavujärjestykselle. Tämä tarkoittaa:

if Filename1 = Filename2 then ... // is not sufficient under OS X
if AnsiCompareFileName(Filename1, Filename2) = 0 then ... // not sufficient under fpc 2.2.2, not even with cwstring
if CompareFilenames(Filename1, Filename2) = 0 then ... // this always works (unit FileUtil or FileProcs

Katso myös