Free pascal unicode stringek


 Hogyan oldhatom meg az karaktersorozat ékezettelenítését free pascal-ban?
Íme a kód, csak épp a közepében lévő pozícióegyeztetés elhasal azon, hogy a az angol és a magyar változó nem egyforma hosszú.
szebb kód itt
function ekezettelen(szoveg:string):string; var magyar,angol: string; f,m: Byte; begin m:=0; magyar:='áéíóöőúüűÁÉÍÓÖŐÚÜŰ'; angol:= 'aeiooouuuAEIOOOUUU'; for f:=1 to length(szoveg) do begin m:=pos(szoveg[f],magyar); if (m<>0) then szoveg[f]:=angol[m]; m:=0; end; ekezettelen:=szoveg; end; begin write(ekezettelen('Árvíztűrő tükörfúrógép')); end.
|
| Akkor ne UTF-8-ban kódolj. |
Talán az egyik legegyszerűbb módszer az ha végigjárjuk az egész paraméterként átadott stringet és azt vizsgálgatjuk hogy a keresett magánhangzók megtalálhatóak e benne. 
(*áéíóöőúüűÁÉÍÓÖŐÚÜŰ*) program ekezetlen; uses crt;
function ekezetnelkuli(szoveg:string):string; var i:byte; begin for i:=1 to length(szoveg) do begin case szoveg[i] of 'á':szoveg[i]:='a'; 'Á':szoveg[i]:='A'; 'é':szoveg[i]:='e'; 'É':szoveg[i]:='E'; 'í':szoveg[i]:='i'; 'Í':szoveg[i]:='I'; 'ó':szoveg[i]:='o'; 'Ó':szoveg[i]:='O'; 'ö':szoveg[i]:='o'; 'Ö':szoveg[i]:='O'; 'ő':szoveg[i]:='o'; 'Ő':szoveg[i]:='O'; 'ú':szoveg[i]:='u'; 'Ú':szoveg[i]:='U'; 'ü':szoveg[i]:='u'; 'Ü':szoveg[i]:='U'; 'ű':szoveg[i]:='u'; 'Ű':szoveg[i]:='U'; end;(*case*) end;(*for*) ekezetnelkuli:=szoveg; end;(*ekezetnelkuli*)
begin (*main*) clrscr; write(ekezetnelkuli('Árvíztűrő tükörfúrógép')); while not keypressed do continue; end. (*main*)
 |
Hallgass NevemTevé-re, és az Unicode-os műveleteknél használd a WideChar ill. WideString típusokat amelyek 16 bites karakterekkel dolgoznak.
Ezenkívűl nézd át legalább vázlatosan az UTF-8 kódolást (azaz, hogy miként kódolják a 16 bites Unicode-ot 8 biten), és akkor megérted, hogy miért nem működik a megoldásod a String típusra. Ugyanis a FreePascal-nak fogalma sincs, hogy abban UTF-8 kódolású adat van, még akkor sem ha az AnsiString-et használod, vagy még az UTF8String típusnál sem. Ezeket alapból 1 bájtos karakterekkel kezeli. Így működik akár a Pos, akár a karakter kiemelés, akár a case. Ha simán szövegkonstanst rakunk beléjük, akkor a Windows alapértelmezett kódlapjával (latin2) dolgozik az ékezetes karaktereknél (ezt jelenti az Ansi), és nem Unicode-ban, ill. nem UTF8-ban.
Tehát jegyezzük meg: Unicode-ot használó programunkban 3 féle kódolással találkozhatunk:
1: WideChar, WideString típusok: Ezek a műveletvégzéshez kellenek. Ezekkel jól működik mind a Pos (van ilyen formája!), mind a case, és a karakter kiválasztás tömbelem szerűen, de 16 bites értékekkel dolgozunk!
2: UTF-8 kódolás: ilyen adatok tárolhatók a bájtelemű string típusokban, de bizonyos műveletek a Pascal-ban nem várt eredményt adnak, mivel egyes karakterek 2 v. több bájton tárolódnak, s a Pascal erről mit se tud. A 16 bites és az UTF8 közötti átkódolást az UTF8Decode() ill. az UTF8Encode() végzi. Ezt a típust spórolás esetén használjuk, vagy ha a bemenő vagy kimenenő adataunk ilyen formátumúak. Az értékadáson kívül ne nagyon végezzünk velük más műveletet (bár az összehasonlítás jól megy a 16 bites értékkel összefüggésben!).
3: Ansi, azaz a Windows alapértelmezett kódlapja - nálunk legtöbbször Latin2 (=ISO8859-2): Ebben csak a 0-127-ig lévő értékek azonosak az UTF8-cal. A többi - közöttük az ékezetesek is - nem azonosak az UTF8 kétbájtos értékeivel illetve az Unicode 16 bites értékekkel se (Latin1 esetén más a helyzet). Sajnos a programszövegünkben lévő ékezetes karakterlánc konstansaink ebben jelennek meg, tehát használatuk majdnem elkerülhetetlen. Az átalakítás ebből (v. ebbe) az AnsiToUTF8() ill. UTF8ToAnsi() fügvényekkel lehetséges. Elvileg a Windows beállítható UTF-8 alapértelmezett karakterkészletre, s ekkor az utóbbi 2 fgv. nem kell, de ebben, és az ezzel járó komlpikációkkal nincs tapasztalatom. Valójában nagy hiányosság, hogy a programszövegünkben Unicode kódolású (16 bites) karakterlánc konstanst olvasható módon nem tudunk megadni - függetlenül a Windows kódlaptól.
A leírtakból kitalálható, hogy az előzőekben olvasható programkódoknak működniük kellene a programba beírt szövegre, de mind hibásan működik az UTF8-ban megadott értékekre. Ha az átkódolandó szöveg UTF8-ban jön, akkor végig kell csinálni a 16 bites mizériát! Ugyanakkor a "magyar" nevű karakterláncba bele kell varázsolnod a magyar ékezetes karakterek Unicode értékeit (vagy FlamingClaw válaszában a case konstansait kell Unicode értékekre cserélni)! |
Az alábbi kóddal meg lehet csinálni amit szeretnél, de még a program forráskódjának karakterkódolása is számít.
program ekezettelenit;
{$mode objfpc}{$H+}
uses SysUtils,Classes;
const Ekezetes : array[0..17] of String=('Á','É','Í','Ó','Ö','Ő','Ú','Ü','Ű', 'á','é','í','ó','ö','ő','ú','ü','ű'); Ekezetmentes : array[0..17] of String=('A','E','I','O','O','O','U','U','U', 'a','e','i','o','o','o','u','u','u'); function StringsReplace(STRBe : String):String; var i : longint; begin For i:=0 to 17 do STRBe:=StringReplace(STRBe,Ekezetes[i],Ekezetmentes[i],[rfReplaceAll]); Result:=STRBe; end;
var Sbe : TStringList; TxtPath,Ski : String; i : longint;
begin WriteLn('Kerem az ekezeteket tartalmazo szovegfajl eleresi utjat: '); ReadLn(TxtPath); if not FileExists(TxtPath) then begin WriteLn('A fajl nem letezik: ',TxtPath); WriteLn('A program futasa veget ert!'); halt(1); end; Sbe:=TStringList.Create; SBe.LoadFromFile(TxtPath); // Ski:=StringsReplace(AnsitoUtf8(Sbe.Text)); Ski:=StringsReplace(Sbe.Text); WriteLn('A beirt szoveg ekezetmentesen: '); WriteLn(Ski); SBe.Free; end.
Egy másik megoldás, amit FlamingClaw is javasolt valahogy így néz ki nálam (bár ezt már egyszer bemásoltam itt a prog.hu-n):
program noekezet; var f1,f2:text; c : char; tbf1,tbf2 : array[1..1048576] of byte; begin if paramcount<2 then begin writeln('A programhasználata:'); writeln(' noekezet fájl1 fájl2'); writeln('ahol a fájl1 az a fájl amit át akarunk alakítani'); writeln('a fájl2 pedig kimeneti fájl amibe az ékezetmentes szöveg kerül'); halt; end; Assign(f1,Paramstr(1)); Assign(f2,Paramstr(2)); settextbuf(f1,tbf1); settextbuf(f2,tbf2); {$i-} Reset(f1); {$i+} if IOREsult<>0 then begin writeln('A fájl nem nyitható meg : ',Paramstr(1)); halt; end;
{$i-} Rewrite(f2); {$i+} if IOREsult<>0 then begin writeln('A fájl nem nyitható meg : ',Paramstr(2)); halt; end;
While not Eof(f1) do begin read(f1,c); if (ord(c)=195) or (ord(c)=197) then begin read(f1,c); case ord(c) of 161 : c:='a'; 129 : c:='A'; 169 : c:='e'; 137 : c:='E'; 173 : c:='i'; 141 : c:='I'; 179 : c:='o'; 147 : c:='O'; 182 : c:='o'; 150 : c:='O'; 145 : c:='o'; 144 : c:='O'; 186 : c:='u'; 154 : c:='U'; 188 : c:='u'; 156 : c:='U'; 177 : c:='u'; 176 : c:='U'; end; end else case ord(c) of 225 : c:='a'; 193 : c:='A'; 233 : c:='e'; 201 : c:='E'; 237 : c:='i'; 205 : c:='I'; 243 : c:='o'; 211 : c:='O'; 246 : c:='o'; 214 : c:='O'; 245 : c:='o'; 213 : c:='O'; 250 : c:='u'; 218 : c:='U'; 252 : c:='u'; 220 : c:='U'; 251 : c:='u'; 219 : c:='U'; end; write(f2,c); end; close(f1); close(f2); end.
Nos remélem segít valamit :). |
|