Leif Andersson 2011-03-06 (-14) Teckenhantering i datorn ======================== Äldre system ------------ Hur skall man lägga in bokstäver i ett dataminne? Datorn kan bara hantera binära siffror som består av ettor och nollor. Så om man vill lägga in en bokstav i ett dataminne måste man tilldela den en binär siffra som man kan lägga in i minnet. Om man bestämmer sig för att alltid knyta en viss bokstav till en viss siffra kan man när man skriver omvandla bokstäverna till lagringsbara siffror och när man läser kan man omvandla dessa siffror till bokstäver. På 1950-talet började man ordna upp information för att kunna hantera den i datorminnen i form av hålkort eller magnetband. På 1970-talet hade MOS-transistorn utvecklats så att man kunde börja bygga prcessorer och minnen i halvledarteknik. Men minneskapacitet var fortfarande dyrt. De första persondatorerna hade arbetsminnen på några få kB. Bill Gates lär ha sagt: "64 kB would be just enough for anybody". Och de tidiga processorena kunde bara hantera minnesadresser med 16 bits vilket innebar att de bara kunde adressera 64 000 minnespositioner. En byte på åtta ettor eller nollor kan anta 256 olika värden. Den kan alltså lagra en siffra som ligger i intervallet 0 till och med 255. Det engelska alfabetet omfattar 26 tecken. Att använda en hel teckenbyte för att ange en engelsk bokstav framstod vid denna tid som ett orimligt slöseri med dyrbar minneskapacitet. Om man ville ha med både stora och små bokstäver behövde man ju bara 26 + 26 = 52 siffror. Tog man med punkt,komma,parenteser med mera fick man ihop ett behov att kunna lagra 64 olika tecken. En byte skulle alltså kunna lagra fyra tecken. Man delade in teckenbyten i fyra nibbles. Till en början förekom en mängd olika sätt att koda bokstäver till siffror. 19XX fastställdes den så kallade ASCII-koden som angav vilken siffra i teckenbytens andra nibble som motsvarade en viss engelsk bokstav. Detta innebar att texter blev läsbara även om man inte visste vilket operativsystem som skapat dem. Det var ett enormt framsteg. Och det kom i en tid när man så smått började utbyta texter via föregångare till Internet. Fortfarande finns det system som inte följer ASCII-koden. Att använda ett eget sätt att lagra tecken är ett sätt att tvinga användarna att köpa hanterings- programmet. Och program för datakomprimering använder möjligheten att lagra flera tecken per byte. Men för ett vanligt tangentbord är de flesta tangenter direkt kopplade till en siffra ur ASCII-koden. Det visade sig snart att engelska inte är världens enda språk. Hur skulle man hantera andra språks specialtecken, till exempel svenskans å, ä och ö? I Microsofts operativsystem DOS använde man en metod med land-kod. Man lade i operativsystemet in en omkodning av specialtecken så att de kunde hanteras via den typ av tangentbord som användes i ett visst land. För Sverige tog man bort tecknen för hakparenteser, måsvingar, backslash och vertikalstreck och lät dem i stället betyda å,ä och ö.(Ä=91,Ö=92,Å=93,ä=123,ö=124,å=125) På det sättet kunde man hantera språk som svenska inom teckenbytens andra nibble. Siffror, skiljetecken med mera la man i övre delen av teckenbytens första nibble. På det sättet fick man ett system där övre halvan av teckenbyten, alltså tredje och fjärde nibble inte användes. Om man ville kunde man alltså lägga in två tecken per byte. Hakparenteser och måsvingar ersatte man med vanlig parentes plus punkt eller stjärna. Men detta sätt att hantera teckenbyten fungerade inte för grekiska, kyrilliska eller arabiska alfabeten. Här fanns i stället en möjlighet att lägga dessa i den övre delen av teckenbyten. Man började använda ett system med charsets. Varje tecken tilldelades en siffra. När man på det sättet definierat 256 tecken fortsatte man genom att använda två bytes för att ange ett tecken. På det sättet kunde man ge greksika, kyriliska och arabiska tecken entydiga siffror. Genom att välja charset kunde man lyfta in en siffergrupp, till exempel den som omfattade kyrilliska bokstäver i teckebytens övre halva. På det sättet blev det möjligt att hantera både det kyrilliska och det latinska (eg engelska) alfabetet. Men tangentbordet kan inte adressera hela teckenbyten. På något sätt måste man ange vilka digitala värden som skall knytas till tangenterna. När man använder metoden med charset blir övre halvan av teckenbyten fri om man inte lägger in något främmande alfabet i den. Man placerade därför vanliga specialtecken som våra å, ä och ö, tyskans ü, tecken med accent, muljerings- tecken och cedilj med mera i denna del av teckenbyten. Det fanns en del olika sätt att använda teckenbytens övre halva men så småningom fick man en ganska allmänt accepterad standard i ANSI-charset. Här ligger Å=197, Ä=196, Ö=214, å=229, ä=228 och ö=246. Unicode och UTF8 ---------------- Med två bytes kan man ange 65 000 olika tecken. Det räcker inte bara till latinska,grekiska, kyrilliska och arabiska alfabeten. Man kan även lägga in matematiska symboler, kinesiska tecken, japanska tecken och mycket mera. Och med tre bytes kan man ange över 16 miljoner tecken. För överskådlig tid är två byte tillräckligt för att skriva på alla nu aktuella språk. Men man måste bestämma sig för vilken siffra som skall representera ett viss tecken. Man skapade då UNICODE som ett system där varje tecken har ett fastställt värde. I dag har en mängd tecken fått ett fastställt UNICODE-nummer. Men fortfarande finns det luckor, det vill säga siffror som ännu inte knutits till något tecken. När man började använda UNICODE hade användningen av ASCII-koden blivit så etablerad att man måste skapa ett system som var bakåt kompatibelt med ASCII-koden. Det självklara sättet att göra det är ju att reservera ett (eller två) tecken som får betyda "Följande två (eller tre) bytes skall läsas som ett flerbytestecken". På det sättet skulle man kunna använda nästan hela teckenbyten för enbytestecken men ändå ha möjlighet att adressera flerbytestecken. Men så gjorde man inte. I stället skapade man UTF8 (och UTF16). I UTF8 används teckenbytens första och andra nibble som för den gamla ASCII-koden. Engelska texter är alltså helt oförändrade. Men ett tecken i teckenbytens övre halva tolkas som inledning till ett flerbytestecken. Detta första tecken anger hur många bytes som ingår i tecknet. Om man skiver tecknets siffra som ett binärt tal börjar det med en etta eftersom det ligger i teckenbytens övre halva. Antalet ettor före första nollan anger antalet bytes som ingår i tecknet. Delen efter första nollan är de mest signifikanta bitarna i teckensiffran. Följande bytes skall i binär form börja med 1 0 och resten av dem är de bits som skall ingå i teckensiffran. Det mest imponerande med UTF8 är att man lyckats få någon att använda ett så krångligt system. Orsaken är att det fungerar väl för engelska bokstäver. En ANSI-kodad engelsk text kan läsas felfritt som om den vore UTF8-kodad. Om man skriver och läser engelska förefaller alltså UTF8 vara ett bra sätt att även få tillgång till alla andra alfabet. Men i en ANSI-kodad svensk text som läses som UTF8-kodad tolkas å, ä och ö som inledande byte i ett flerbytes- tecken. Men trots allt verkar det som om UTF8 är på väg att bli allmänt accepterat som tecken-kod. Det är nog bara att bita i det sura äpplet och gilla läget. UTF8 har fördelen att man fritt kan blanda olika alfabet i en text. Att man skulle kunna göra det på mycket enklare sätt är nog bara att glömma bort. Textformatering --------------- För att skriva ut eller visa en text på bildskärm behövs två typer av information, dels information om vilka bokstäver som skall visas dels information om var de skall stå och om hur de skall se ut. Information om plats och utseende kallas för textformatering. Ovillkorlig radbrytning intar en mellanställning. Det är ju egentligen en textformatering men den brukar betraktas som en del av den oformaterade textfilen. Ovillkorligt radskift skrivs som två tecken med numren 13 (ny rad) och 10 (retur till radbörjan). När man skriver en text gör man det för att någon skall läsa den. Om man bara vill överföra ett enkelt budskap vill man att läsaren skall få veta vilka bokstäver som ingår i texten. Hur bokstäverna skall se ut och hur de skall grupperas kan man då överlåta till läsaren att bestämma. Man vill alltså skriva en oformaterad textfil som endast innehåller teckennumren för de tecken man skrivit. Detta är speciellt viktig om man skriver en källkod som skall läsas av en kompilator eller interpretator. Hur en bokstav ser ut bestäms av den font man väljer. En font är en uppsättning bokstavsbilder (glyfer) där varje glyf är knuten till ett bokstavsnummer. Om man väljer en viss font och läser en oformaterad textfil får man alltså för varje tecken i textfilen den glyf som motsvarar tecknets nummer. En oformaterad textfil innehåller ingen information om placering och utseende för bokstäverna förutom att de skall stå i samma ordning som i textfilen. Men ibland vill man när man skriver en text kunna ange hur den skall visas. Man skriver då en formaterad text som utöver bokstavsnummer även innehåller formateringstecken. Det finns en mängd olika sätt att göra detta. Jag tar här upp två sätt HTML och RichEdit. HTML ---- Texter som läggs ut på Internet skrivs vanligen i HTML-format (Hyper Text Markup Language). I en html-text kan man skriva in tags som inte visas utan tolkas som instruktioner om hur texten skall visas. Tags skrivs mellan < och >. Om man till exempel vill att ett stycke i texten skall visas med en speciell font inleder man stycket med en tag som talar om vilken font som skall användas och man avslutar stycket med en slutmarkering som anger återgång till tidigare font. Html-texter kan vara UTF8-kodade. För att säkerställa att en UTF8-kodad text läses på rätt sätt kan man före den egentliga texten lägga in en META-tag enligt < META content="text/html; charset=utf-8" http-equiv=Content-Type > (För att denna tag skall visas i stället för att tolkas har jag lagt ett mellanslag efter < och ett mellanslag före > , för att taggen skall fungera tar man bort dessa mellanslag). HTML har också ett utmärkt sätt att ange teckennummer. Man kan skriva & #945; .Tar man bort mellanslaget mellan & och # blir resultatet α , det vill säga det tecken som har unicode-numret 945. På det sättet är det till exempel enkelt att skriva matematiska symboler som & #8800; = ≠ , & #8776; = ≈ , & #8730; = √ . I html-text gäller inte vanliga radbrytningar. Texten anpassas till att passa den yta där den skall visas. Om man vill ha en radbrytning på ett visst ställe använder man taggen < br > som inte behöver någon slutmarkering. Vill man att inlagda radbrytningar skall gälla använder man taggen < pre > som betyder "preformaterad text" och gäller fram till slutmarkeringen < /pre >. RichEdit -------- RichEdit är en formaterad text med ett filhuvud och inlagda tags. En RichEdit- tag inleds med \. Men man kan inte skriva in tags i texten. Skriver man \ läggs \\ in vilket läses som \. Vill man lägga in tags i en RichEdit-text måste man alltså skriva in dem och spara filen med något program som kan hantera oformaterad text. Filhuvudet börjar med {\rtf .Därefter följer diverse information om texten, till exempel vilka fonter som förekommer och vilka färger som förekommer. Tags inne i texten kan så anropa fonter och färger som definierats i filhuvudet. Taggen \u anger att följande siffra fram till avslutande ? är ett unicode- nummer. Vid läsning visas då det tecken som har detta nummer. \u945? ger alltså tecknet α. I Bruksanvisningen i LexSup finns en utförligare beskrivning av hur RichEdit fungerar (se "Om textformatering"). Teckenuppsättning ----------------- Om jag vill skriva kinesiska tecken måste jag använda en font som innehåller kinesiska tecken. I Windows XP kan man gå Start - Alla program - Tillbehör - Systemverktyg - Teckenuppsättning. Det startar ett program som visar vilka tecken som finns i de fonter som finns installerade på datorn. Om kinesiska eller andra tecken saknas på datorn kan man i Windows XP gå in på Kontrollpanelen och välja Nationella inställningar. Man får då upp en dialogruta där det finns en tab som heter Språk. Klickar man på den får man möjlighet att lägga in östasiatiska språk (bland annat). Om Anteckningar --------------- Det kan naturligtvis finnas tillfällen där man kan acceptera att dolda styrtecken läggs in i en text för att den skall visas på rätt sätt. Men i vanliga fall vill jag att datorn skall lagra det jag skriver och ingenting annat. En stor fördel med Anteckningar är att om man lagrar filer i text- format (.txt) brukar de lagras som oformaterad text. Det gör att Anteckningar är användbart för att skriva källkod för till exempel Pascal och Java. Det finns emellertid ett fall där Anteckningar kan förstöra en fil genom att lägga in en inledande markering. Det är för UTF8-text. Tar man in en UTF8-kodad text i Anteckningar och sedan sparar den händer det att Anteckningar lägger in UTF8-märket, det vill säga bytevärdena 239, 187 och 191 vilket motsvarar unicode-tecknen ï » ¿ . Teckenhantering i LexSup ------------------------ LexSup är en ordbehandlare som kan slå upp i lexikon. Den kan laddas ner från http://www.lexsup.se. LexSup är skrivet i programspråket Delphi6 och har alltså de egenskaper som detta programspråk medger. Det innebär att LexSup kan hantera oformaterad text och RichEdit. Däremot kan det inte hantera UTF8-kod. Även om man alltså kan åstadkomma formaterad text med LexSup är det knappast någon ide att göra det. Det finna andra program som är bättre om man vill formatera en oformaterad text. LexSup är i första hand tänkt för att: Skriva och läsa med lexikonstöd. Skriva och läsa vanlig oformaterad text utan dolda formateringsinslag. Skriva html-text. Skriva texter med främmande skrivtecken. LexSup använder tre rutor för att visa skriven text. 1 Utfilrutan som är en RichEditruta. 2 Memoruta. 3 Browserruta Utfilrutan visar texten tolkad som om den var ANSI.kodad. Memorutan visar texten tolkad enligt valt charset. Browserrutan visar hur texten ser ut i en browserruta med den inställning av browsern som man har vid tillfället. Delphi6 ger inte stöd för UTF8 och LexSup kan därför inte hantera UTF8-text. I övrigt kan man hämta formaterade filer som oformaterade om man vill se alla formateringstecken som ingår i dem. Om man hämtar en fil till Utfilrutan får man också möjlighet att "Visa Hackerbild". Diskfilen läses då in som en bytesfil och resultatet visas i två rutor intill varandra. I den vänstra visas varje bytes värde som en hexadecimal siffra och i den högra visas varje byte tolkad som ett ANSI-kodat tecken. På det sättet kan man alltså granska filer som ger egendomliga resultat. Ofta beror sådant på att man använt något program som smugit in dolda formateringstecken. När det gäller främmande tecken finns det i LexSup en metod och rester av en äldre metod. För att kunna skriva (och läsa) kyrilliska bokstäver gjorde jag en font där jag flyttade in det kyrilliska alfabetet i fjärde nibble. Via "Options - Främmande Latinskt till Special" kan man ställa om tangentbordet så att det knyts till textbytens fjärde nibble i stället för till andra nibble. Detta fungerade för kyrilliska, grekiska och även arabiska alfabeten men inte för kinesiska eller japanska skrivtecken. Jag lade så in Musskrift och en möjlighet att förskjuta tangentbordet. Det blev då möjligt att nå hela teckenbyten, antingen via Musskrift eller via förskjutet tangentbord. Därmed gick det att använda charset i stället för att göra särskilda fonter. Och om man låter programmet kombinera två tecken till ett tvåbytestecken får man möjlighet att skriva i tvåbytesmod som kan adressera kinesiska tecken. Kinesiska tecken (förenklade) finns i charset 134. Väljer man charset 134 sätts LexSup i tvåbytesmod. De tecken man skriver visas i Utfilruta var för sig som ANSI-tecken och i Memorutan visas de kinesiska tecken som motsvarar ett teckenpar. I Mustecken ingår en möjlighet att koda om teckenrutorna. Den var från början tänkt för att man skulle kunna lägga vanliga ord eller fraser på de tecken- rutor som sällan användes. Denna möjlighet kan användas för att koda om kinesiska tecken. Lägger man filen "mustecken.tab" i det svensk-kinesiska lexikonet kan man där koda om tecken. I charset 134 används inte värdena 0 - 64 som värde på andra byte. Man kan alltså lägga vilka tecken man vill på dessa teckenrutor. Man kan då dela in de vanligaste tecknen i grupper om 32 tecken. När man skriver första tecknet i ett teckenpar väljer man 32-grupp. Det går då att lägga in de tecken som ingår i gruppen i de teckenrutor som hör till teckenbytens första nibble. När man så skriver ett sådant tecken skrivs det ut tillsammans med första tecknet och ger ett kinesiskt tecken i Memorutan. Genom att knyta tangentbordet till Mustecken blev det även möjligt att skriva kinesiska tecken med två tangenttryckningar. För närvarande finns c:a 1000 av de vanligaste kinesiska tecknen inlagda så att de är åtkomliga via Tvåbytestangentbordet eller via Musskrift. Och i det svensk-kinesiska lexikonet finns c:a 7000 uppslagsord som man kan nå via dubbelkomma. Teckenhantering i LexSupLaz --------------------------- Det finns nu ett programpaket som heter Lazarus. Det är mycket likt Delphi men medan Delphi är ett programpaket som säljs av Borland är Lazarus fritt tillgängligt och kan laddas ner från http://sourceforge.net/projects/lazarus/ Jag har överfört och skrivit om en del av LexSup för Lazarus. Jag kallar resultatet för LexSupLaz. En stor skillnad mellan Delphi och Lazarus är att Delphi inte kan hantera UTF8 medan all teckenhantering i Lazarus är UTF8-baserad. Fördelen med UTF8 är att man kan blanda enbytestecken och tvåbytestecken. Metoden att använda en särskild Memoruta för att visa tecken enligt valt charset är alltså inte aktuell i LexSupLaz. Det man skriver blir UTF8-kodat vare sig det är enbytes eller tvåbytestecken. En annan skillnad mellan Delphi och Lazarus är att Lazarus inte stöder RichEdit. Det finns inte i Lazarus något stöd för att skriva formaterad text. LexSupLaz kan alltså bara åstadkomma oformaterad text. I LexSupLaz har Musskrift fått en knapp som heter TB2. Klickar man på den byter den namn till Normal och LexSupLaz sätts i ovillkorlig tvåbytesmod. Skriver man två tecken tolkas de då som ett teckenpar som ger ett tvåbytes- tecken oavsett vilken nibble det första tecknet ligger i. VARNING: LEXSUPLAZ är inte färdigt!! Det finns för närvarande inga spärrar mot oavsiktlig radering eller överskrivning! Fig 1 Teckenkoder i DOS Fig 2 Äldre användning av hela teckenbyten Fig 3 Teckenbyten enl ANSI och UNICODE