UTF8 strings and characters/fi: what changed
Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.
Title: UTF8 strings and characters/fi
| Old | New | Line | |
|---|---|---|---|
| 1 | + | # UTF-8 merkit ja merkkijonot | |
| 2 | + | ||
| 3 | + | ## UTF-8:n kauneus | |
| 4 | + | ||
| 5 | + | Tavut joiden ylin bitti on '0' (0xxxxxxx) on varattu [[ASCII/fi|ASCII]]- yhteensopiville yhden tavun merkille. Monitavuisilla 1: n lukumäärä ensimmäisessä tavussa määrää koodin tavujen tavujen määrän. Esimerkit : | |
| 6 | + | ||
| 7 | + | - 1 tavu : 0xxxxxxx | |
| 8 | + | - 2 tavua : 110xxxxx 10xxxxxx | |
| 9 | + | - 3 tavua : 1110xxxx 10xxxxxx 10xxxxxx | |
| 10 | + | - 4 tavua : 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx | |
| 11 | + | ||
| 12 | + | Merkistökoodaus [[UTF-8]]:n suunnittelussa on joitain etuja verrattuna muihin koodauksiin: | |
| 13 | + | ||
| 14 | + | - 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ä. | |
| 15 | + | ||
| 16 | + | Kuitenkin tämä taaksepäin yhteensopivuus ei ulotu koodiin, koska koodia on käsiteltävä niin että vältetään utf8-merkkijonoja. | |
| 17 | + | ||
| 18 | + | - Monitavuisen datan eheys voidaan todentaa '1'-bittien määrästä kunkin tavun alussa. | |
| 19 | + | - Aina löytyy monitavuisen kooditavun alkukohta, vaikka hyppättäisiin satunnaisen tavun paikkaan. | |
| 20 | + | - 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. | |
| 21 | + | ||
| 22 | + | Huomaa, että UTF-16: ssä on samanlaisia eheysominaisuuksia. (D800-alue signaalit ensin korvikkeena, DC00-alue signaalit toissijaisen korvaavan osan) | |
| 23 | + | ||
| 24 | + | - 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. | |
| 25 | + | - 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. | |
| 26 | + | ||
| 27 | + | ## Esimerkit | |
| 28 | + | ||
| 29 | + | 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: | |
| 30 | + | ||
| 31 | + | - iterointi tavujen yli - hyödyllinen alimerkkijonon etsimiseksi tai kun tarkastellaan vain UTF8-merkkijonon ASCII-merkkejä, esimerkiksi XML-tiedostojen jäsentämisessä. | |
| 32 | + | - iterointi koodipisteiden tai merkkien yli - hyödyllinen graafisille komponenteille kuten [[SynEdit]], esimerkiksi kun halutaan tietää kolmannen tulostettavan merkin näytöllä. | |
| 33 | + | ||
| 34 | + | ### Alimerkkijonon etsiminen | |
| 35 | + | ||
| 36 | + | 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: | |
| 37 | + | ||
| 38 | + | ``` pascal | |
| 39 | + | uses LazUTF8; | |
| 40 | + | ... | |
| 41 | + | procedure Where(SearchFor, aText: string); | |
| 42 | + | var | |
| 43 | + | BytePos: LongInt; | |
| 44 | + | CodepointPos: LongInt; | |
| 45 | + | begin | |
| 46 | + | BytePos:=Pos(SearchFor,aText); | |
| 47 | + | CodepointPos:=UTF8Pos(SearchFor,aText); | |
| 48 | + | writeln('The substring "',SearchFor,'" is in the text "',aText,'"', | |
| 49 | + | ' at byte position ',BytePos,' and at codepoint position ',CodepointPos); | |
| 50 | + | end; | |
| 51 | + | ``` | |
| 52 | + | ||
| 53 | + | ### Etsi ja kopioi | |
| 54 | + | ||
| 55 | + | 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. | |
| 56 | + | ||
| 57 | + | ``` pascal | |
| 58 | + | function SplitInHalf(Txt, Separator: string; out Half1, Half2: string): Boolean; | |
| 59 | + | var | |
| 60 | + | i: Integer; | |
| 61 | + | begin | |
| 62 | + | i := Pos(Separator, Txt); | |
| 63 | + | Result := i > 0; | |
| 64 | + | if Result then | |
| 65 | + | begin | |
| 66 | + | Half1 := Copy(Txt, 1, i-1); | |
| 67 | + | Half2 := Copy(Txt, i+Length(Separator), Length(Txt)); | |
| 68 | + | end; | |
| 69 | + | end; | |
| 70 | + | ``` | |
| 71 | + | ||
| 72 | + | ### Iterointi merkkijonon yli etsien ASCII merkkejä | |
| 73 | + | ||
| 74 | + | 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ä. | |
| 75 | + | ||
| 76 | + | ``` pascal | |
| 77 | + | procedure ParseAscii(Txt: string); | |
| 78 | + | var | |
| 79 | + | i: Integer; | |
| 80 | + | begin | |
| 81 | + | for i:=1 to Length(Txt) do | |
| 82 | + | case Txt[i] of | |
| 83 | + | '(': PushOpenBracketPos(i); | |
| 84 | + | ')': HandleBracketText(i); | |
| 85 | + | end; | |
| 86 | + | end; | |
| 87 | + | ``` | |
| 88 | + | ||
| 89 | + | ### Iterointi merkkijonon yli etsien Unikoodi merkkejä tai tekstiä | |
| 90 | + | ||
| 91 | + | Jos halutaan löytää merkkijonossa kaikki tietyn merkin tai alimerkkijonon esiintymät niin kutsutaan PosEx()-funktiota toistuvasti. | |
| 92 | + | ||
| 93 | + | 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. | |
| 94 | + | ||
| 95 | + | ``` pascal | |
| 96 | + | procedure ParseUnicode(Txt: string); | |
| 97 | + | var | |
| 98 | + | Ch1, Ch2, Ch3: String; | |
| 99 | + | i: Integer; | |
| 100 | + | begin | |
| 101 | + | Ch1 := 'Й'; // Characters to search for. They can also | |
| 102 | + | Ch2 := 'ﯚ'; // be combined codepoints or longer text. | |
| 103 | + | Ch3 := 'Å'; | |
| 104 | + | for i:=1 to Length(Txt) do | |
| 105 | + | begin | |
| 106 | + | if Copy(Txt, i, Length(Ch1)) = Ch1 then | |
| 107 | + | DoCh1(...) | |
| 108 | + | else if Copy(Txt, i, Length(Ch2)) = Ch2 then | |
| 109 | + | DoCh2(...) | |
| 110 | + | else if Copy(Txt, i, Length(Ch3)) = Ch3 then | |
| 111 | + | DoCh3(...) | |
| 112 | + | end; | |
| 113 | + | end; | |
| 114 | + | ``` | |
| 115 | + | ||
| 116 | + | Silmukkaa voidaan optimoida hyppäämällä jo käsiteltävien osien päälle. | |
| 117 | + | ||
| 118 | + | ### Merkkijonon yli iterointi analysoimalla yksittäisiä koodipisteitä | |
| 119 | + | ||
| 120 | + | Tämä koodi kopioi kunkin koodipisteen String-tyyppiseen muuttujaan, jota voidaan sitten käsitellä edelleen. | |
| 121 | + | ||
| 122 | + | ``` pascal | |
| 123 | + | procedure IterateUTF8(S: String); | |
| 124 | + | var | |
| 125 | + | CurP, EndP: PChar; | |
| 126 | + | Len: Integer; | |
| 127 | + | ACodePoint: String; | |
| 128 | + | begin | |
| 129 | + | CurP := PChar(S); // if S='' then PChar(S) returns a pointer to #0 | |
| 130 | + | EndP := CurP + length(S); | |
| 131 | + | while CurP < EndP do | |
| 132 | + | begin | |
| 133 | + | Len := UTF8CodepointSize(CurP); | |
| 134 | + | SetLength(ACodePoint, Len); | |
| 135 | + | Move(CurP^, ACodePoint[1], Len); | |
| 136 | + | // A single codepoint is copied from the string. Do your thing with it. | |
| 137 | + | ShowMessageFmt('CodePoint=%s, Len=%d', [ACodePoint, Len]); | |
| 138 | + | // ... | |
| 139 | + | inc(CurP, Len); | |
| 140 | + | end; | |
| 141 | + | end; | |
| 142 | + | ``` | |
| 143 | + | ||
| 144 | + | ### Tavujen käyttäminen yhdellä UTF8-koodipisteellä | |
| 145 | + | ||
| 146 | + | 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: | |
| 147 | + | ||
| 148 | + | ``` pascal | |
| 149 | + | uses LazUTF8; | |
| 150 | + | ... | |
| 151 | + | procedure DoSomethingWithString(AnUTF8String: string); | |
| 152 | + | var | |
| 153 | + | p: PChar; | |
| 154 | + | CPLen: integer; | |
| 155 | + | FirstByte, SecondByte, ThirdByte, FourthByte: Char; | |
| 156 | + | begin | |
| 157 | + | p:=PChar(AnUTF8String); | |
| 158 | + | repeat | |
| 159 | + | CPLen := UTF8CodepointSize(p); | |
| 160 | + | ||
| 161 | + | // Here you have a pointer to the char and its length | |
| 162 | + | // You can access the bytes of the UTF-8 Char like this: | |
| 163 | + | if CPLen >= 1 then FirstByte := P[0]; | |
| 164 | + | if CPLen >= 2 then SecondByte := P[1]; | |
| 165 | + | if CPLen >= 3 then ThirdByte := P[2]; | |
| 166 | + | if CPLen = 4 then FourthByte := P[3]; | |
| 167 | + | ||
| 168 | + | inc(p,CPLen); | |
| 169 | + | until (CPLen=0) or (p^ = #0); | |
| 170 | + | end; | |
| 171 | + | ``` | |
| 172 | + | ||
| 173 | + | ### Pääsy N:teen UTF8-koodipisteeseen | |
| 174 | + | ||
| 175 | + | Iteraation lisäksi voi olla myös halu päästä satunnaiseen UTF-8-koodipisteeseen. | |
| 176 | + | ||
| 177 | + | ``` pascal | |
| 178 | + | uses LazUTF8; | |
| 179 | + | ... | |
| 180 | + | var | |
| 181 | + | AnUTF8String, NthCodepoint: string; | |
| 182 | + | begin | |
| 183 | + | NthCodepoint := UTF8Copy(AnUTF8String, N, 1); | |
| 184 | + | ``` | |
| 185 | + | ||
| 186 | + | ### Näytetään koodipisteet UTF8CodepointToUnicode-ohjelmalla | |
| 187 | + | ||
| 188 | + | Seuraavassa on esimerkki siitä, miten kunkin koodipisteen 32 bittisen koodipisteen arvo näytetään UTF8-merkkijonona: | |
| 189 | + | ||
| 190 | + | ``` pascal | |
| 191 | + | uses LazUTF8; | |
| 192 | + | ... | |
| 193 | + | procedure IterateUTF8Codepoints(const AnUTF8String: string); | |
| 194 | + | var | |
| 195 | + | p: PChar; | |
| 196 | + | unicode: Cardinal; | |
| 197 | + | CPLen: integer; | |
| 198 | + | begin | |
| 199 | + | p:=PChar(AnUTF8String); | |
| 200 | + | repeat | |
| 201 | + | unicode:=UTF8CodepointToUnicode(p,CPLen); | |
| 202 | + | writeln('Unicode=',unicode); | |
| 203 | + | inc(p,CPLen); | |
| 204 | + | until (CPLen=0) or (unicode=0); | |
| 205 | + | end; | |
| 206 | + | ``` | |
| 207 | + | ||
| 208 | + | ## Hajotetut merkit | |
| 209 | + | ||
| 210 | + | 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. | |
| 211 | + | ||
| 212 | + | ### macOS | |
| 213 | + | ||
| 214 | + | 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: | |
| 215 | + | ||
| 216 | + | ``` pascal | |
| 217 | + | if Filename1 = Filename2 then ... // is not sufficient under OS X | |
| 218 | + | if AnsiCompareFileName(Filename1, Filename2) = 0 then ... // not sufficient under fpc 2.2.2, not even with cwstring | |
| 219 | + | if CompareFilenames(Filename1, Filename2) = 0 then ... // this always works (unit FileUtil or FileProcs | |
| 220 | + | ``` | |
| 221 | + | ||
| 222 | + | ## Katso myös | |
| 223 | + | ||
| 224 | + | - [[Character and string types]] | |
| 225 | + | ||
| 226 | + | --- | |
| 227 | + | *From the Free Pascal wiki, page "UTF8 strings and characters/fi", as it stood on 2020-03-04 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).* |
