Programiranje

Poglobljen pogled na vrsto znakov Java

Različica Java 1.1 uvaja številne razrede za obravnavo znakov. Ti novi razredi ustvarijo abstrakcijo za pretvorbo iz pojma vrednosti znakov, specifičnega za platformo, v Unicode vrednote. Ta stolpec obravnava, kaj je bilo dodano, in motivacijo za dodajanje teh razredov znakov.

Tip char

Morda najbolj zlorabljen osnovni tip v jeziku C je tip char. The char type delno zlorabljen, ker je opredeljen kot 8 bitov, v zadnjih 25 letih pa je 8 bitov opredelil tudi najmanjši nedeljiv del pomnilnika v računalnikih. Ko združite slednje dejstvo z dejstvom, da je bil nabor znakov ASCII definiran tako, da ustreza 7 bitom, se char type je zelo priročen "univerzalni" tip. Nadalje, v C, kazalec na spremenljivko tipa char je postal univerzalni tip kazalca, ker je vse, na kar se lahko sklicuje kot char se lahko z uporabo ulivanja sklicuje tudi na katero koli drugo vrsto.

Uporaba in zloraba char type v jeziku C je privedel do številnih nezdružljivosti med izvedbami prevajalnika, zato sta bili v standardu ANSI za C narejeni dve posebni spremembi: Univerzalni kazalnik je bil na novo definiran tako, da ima vrsto void, zato je programer zahteval izrecno izjavo; Številčna vrednost znakov pa se je štela za podpisano, s čimer je bilo določeno, kako bodo obravnavani, če se bodo uporabljali pri numeričnih izračunih. Nato so sredi osemdesetih inženirji in uporabniki ugotovili, da 8 bitov ne zadostuje za predstavitev vseh znakov na svetu. Na žalost je bil takrat C že tako zasidran, da ljudje niso bili pripravljeni, morda celo nesposobni, spremeniti definicijo char tip. Zdaj bliskajte naprej v devetdeseta leta, na zgodnje začetke Jave. Eno od številnih načel, ki so bila določena pri oblikovanju jezika Java, je bilo, da je število znakov 16 bitov. Ta izbira podpira uporabo Unicode, standardni način predstavljanja različnih vrst znakov v različnih jezikih. Na žalost je postavil temelje tudi za številne težave, ki se šele odpravljajo.

Kaj sploh je lik?

Vedel sem, da imam težave, ko sem se vprašal: "Pa kaj je znak? "No, lik je črka, kajne? Kup črk sestavlja besedo, besede tvorijo stavke itd. V resnici pa je, da je razmerje med predstavitvijo lika na računalniškem zaslonu , ki se imenuje glif, na številčno vrednost, ki določa ta glif, imenovan a kodna točka, v resnici sploh ni enostaven.

Menim, da imam srečo, da sem materni govorec angleškega jezika. Prvič, ker je bil to skupni jezik velikega števila tistih, ki so prispevali k oblikovanju in razvoju sodobnega digitalnega računalnika; drugič, ker ima razmeroma majhno število glifov. V definiciji ASCII je 96 znakov za tiskanje, ki jih lahko uporabimo za pisanje angleščine. Primerjajte to s kitajščino, kjer je opredeljenih več kot 20.000 glifov in je ta definicija nepopolna. Že od zgodnjih začetkov Morsejeve in Baudotove kode je zaradi splošne enostavnosti (malo glifov, statistična pogostost pojavljanja) angleškega jezika postala lingua-franca digitalne dobe. Ker pa se je število ljudi, ki vstopajo v digitalno dobo, povečalo, se je povečalo tudi število tujih govorcev angleščine. Ko so številke naraščale, je bilo vse več ljudi vse bolj nenaklonjenih sprejetju, da računalniki uporabljajo ASCII in govorijo samo angleško. To je močno povečalo število "znakov" računalnikov, ki jih je bilo treba razumeti. Posledično se je moralo število glifov, ki jih kodirajo računalniki, podvojiti.

Število razpoložljivih znakov se je podvojilo, ko je bila častitljiva 7-bitna koda ASCII vključena v 8-bitno kodiranje znakov, imenovano ISO Latin-1 (ali ISO 8859_1, "ISO" pa je Mednarodna organizacija za standarde). Kot ste morda razumeli pri imenu kodiranja, je ta standard omogočal predstavitev številnih jezikov, ki izhajajo iz latinščine, ki se uporabljajo na evropski celini. Samo zato, ker je bil standard ustvarjen, pa še ni pomenilo, da je uporaben. Takrat je veliko računalnikov že začelo uporabljati ostalih 128 "znakov", ki bi jih lahko v nekaj prednosti predstavljal 8-bitni znak. Dva ohranjena primera uporabe teh dodatnih znakov sta IBM-ov osebni računalnik (PC) in najbolj priljubljen računalniški terminal doslej, Digital Equipment Corporation VT-100. Slednji živi v obliki programske opreme za emulator terminalov.

O dejanskem času smrti 8-bitnega znaka se bo nedvomno razpravljalo desetletja, vendar ga pripisujem ob uvedbi računalnika Macintosh leta 1984. Macintosh je v osnovno računalništvo vnesel dva zelo revolucionarna koncepta: pisave znakov, ki so bile shranjene v OVEN; in WorldScript, ki se lahko uporablja za predstavitev znakov v katerem koli jeziku. Seveda je bila to preprosto kopija tistega, kar je Xerox pošiljal na svojih strojih razreda Dandelion v obliki sistema za obdelavo besedil Star, toda Macintosh je te nove nabore znakov in pisave prinesel občinstvu, ki je še vedno uporabljalo "neumne" terminale. . Ko se je začelo, uporabe različnih pisav ni bilo več mogoče ustaviti - preveč privlačno je bilo za preveč ljudi. Konec 80-ih se je pritisk na standardizacijo uporabe vseh teh znakov pojavil z ustanovitvijo konzorcija Unicode, ki je svojo prvo specifikacijo objavil leta 1990. Na žalost se je v 80-ih in celo v 90-ih pomnoženo število naborov znakov. Zelo malo inženirjev, ki so takrat ustvarjali nove znakovne kode, je menilo, da je nastajajoči standard Unicode izvedljiv, zato so ustvarili svoje preslikave kod v glife. Torej, čeprav Unicode ni bil dobro sprejet, stališče, da je na voljo le 128 ali največ 256 znakov, zagotovo ni več. Po Macintosh-u je podpora za različne pisave postala nujna funkcija za obdelavo besedil. Osem bitnih likov je izginjalo.

Java in Unicode

V zgodbo sem vstopil leta 1992, ko sem se pridružil skupini Oak (jezik Java se je ob prvem razvoju imenoval Oak) pri podjetju Sun. Osnovni tip char je bil opredeljen kot 16 nepodpisanih bitov, edina nepodpisana vrsta v Javi. Utemeljitev 16-bitnega znaka je bila, da bo podpiral kakršno koli predstavitev znakov Unicode, s čimer bo Java primerna za zastopanje nizov v katerem koli jeziku, ki ga podpira Unicode. Toda to, da lahko predstavljam niz in ga lahko natisnem, je bila vedno ločena težava. Glede na to, da je večina izkušenj v skupini Oak prihajala iz sistemov Unix in sistemov, pridobljenih iz sistema Unix, je bil najudobnejši nabor znakov spet ISO Latin-1. Tudi z dediščino skupine Unix je bil sistem I / O Java v veliki meri oblikovan po abstrakciji toka Unix, pri čemer je bila vsaka V / I naprava lahko predstavljena s tokom 8-bitnih bajtov. Ta kombinacija je v jeziku med 8-bitno vhodno napravo in 16-bitnimi znaki Jave povzročila napačne lastnosti. Tako je bilo povsod, kjer je bilo treba Java nize brati ali zapisovati v 8-bitni tok, obstajati majhen bit kode, kramp, ki je 8-bitne znake čarobno preslikal v 16-bitni unicode.

V različicah 1.0 Java Developer Kit (JDK) je bil vhodni kramp v DataInputStream razred in izhodni kramp je bil celoten PrintStream razred. (Pravzaprav je bil vhodni razred imenovan TextInputStream v različici alfa 2 Java, vendar jo je nadomestil DataInputStream kramp v dejanski izdaji.) To še naprej povzroča težave začetnikom Java programerjev, saj obupno iščejo Java ekvivalent funkcije C getc (). Razmislite o naslednjem programu Java 1.0:

uvoz java.io. *; javni razred lažen {public static void main (String args []) {FileInputStream fis; DataInputStream dis; char c; poskusite {fis = new FileInputStream ("data.txt"); dis = nov DataInputStream (fis); while (true) {c = dis.readChar (); System.out.print (c); System.out.flush (); if (c == '\ n') break; } fis.close (); } ulov (izjema e) {} System.exit (0); }} 

Na prvi pogled se zdi, da ta program odpre datoteko, jo prebere po en znak in zapre, ko se prebere prva nova vrstica. V praksi pa dobite neželene podatke. In razlog, da dobite kramo, je ta readChar bere 16-bitne znake Unicode in System.out.print natisne tisto, za kar domneva, da je 8-bitni znak ISO Latin-1. Če pa zgornji program spremenite tako, da bo uporabil readLine funkcija DataInputStream, se zdi, da deluje, ker je koda v readLine bere obliko, ki je s prehodnim kimanjem k specifikaciji Unicode definirana kot "spremenjen UTF-8". (UTF-8 je oblika, ki jo Unicode določi za zastopanje znakov Unicode v 8-bitnem vhodnem toku.) Tako je v Javi 1.0 situacija, da so Java nizi sestavljeni iz 16-bitnih znakov Unicode, vendar obstaja samo ena preslikava, ki preslika Znaki ISO Latin-1 v Unicode. Na srečo Unicode definira kodno stran "0" - torej 256 znakov, katerih zgornjih 8 bitov je nič -, da natančno ustreza naboru ISO Latin-1. Tako je preslikava precej nepomembna in dokler uporabljate samo datoteke z znaki ISO Latin-1, ne boste imeli težav, ko bodo podatki zapustili datoteko, jih bo obdelal razred Java in nato prepisal v datoteko .

Pri zakopavanju vhodne kode za pretvorbo v te razrede sta bili dve težavi: Vse platforme niso shranile večjezičnih datotek v spremenjeni obliki UTF-8; in vsekakor aplikacije na teh platformah niso nujno pričakovale nelatiničnih znakov v tej obliki. Zato je bila podpora za izvajanje nepopolna in v poznejši izdaji ni bilo mogoče preprosto dodati potrebne podpore.

Java 1.1 in Unicode

Izdaja Java 1.1 je predstavila povsem nov nabor vmesnikov za obdelavo znakov, imenovan Bralci in Pisatelji. Spremenil sem razred z imenom lažno od zgoraj v razred z imenom kul. The kul razred uporablja InputStreamReader razred za obdelavo datoteke namesto datoteke DataInputStream razred. Upoštevajte to InputStreamReader je podrazred novega Bralec razred in System.out je zdaj a PrintWriter objekt, ki je podrazred Pisatelj razred. Koda za ta primer je prikazana spodaj:

uvoz java.io. *; javni razred cool {public static void main (String args []) {FileInputStream fis; InputStreamReader irs; char c; poskusite {fis = new FileInputStream ("data.txt"); irs = nov InputStreamReader (fis); System.out.println ("Uporaba kodiranja:" + irs.getEncoding ()); while (true) {c = (char) irs.read (); System.out.print (c); System.out.flush (); if (c == '\ n') break; } fis.close (); } ulov (izjema e) {} System.exit (0); }} 

Glavna razlika med tem primerom in prejšnjim seznamom kod je uporaba datoteke InputStreamReader razred, ne pa DataInputStream razred. Drug način, na katerega se ta primer razlikuje od prejšnjega, je, da obstaja dodatna vrstica, ki izpiše kodiranje, ki ga uporablja InputStreamReader razred.

Pomembno je, da obstoječa koda, nekoč nedokumentirana (in navidezno neznana) in vdelana v izvajanje getChar metoda DataInputStream razred, je bil odstranjen (njegova uporaba je dejansko zastarela; v prihodnji izdaji bo odstranjena). V različici Jave 1.1 je mehanizem, ki izvaja pretvorbo, zdaj vključen v Bralec razred. Ta enkapsulacija omogoča način, da knjižnice razredov Java podpirajo številne različne zunanje predstavitve nelatiničnih znakov, medtem ko interno vedno uporabljajo Unicode.

Seveda, tako kot prvotna zasnova V / I podsistema, obstajajo simetrični primerki bralnih razredov, ki izvajajo pisanje. Razred OutputStreamWriter se lahko uporablja za zapisovanje nizov v izhodni tok, razred BufferedWriter doda plast medpomnilnika itd.

Trgovanje z bradavicami ali resnični napredek?

Nekoliko vzvišen cilj oblikovanja Bralec in Pisateljrazredi naj bi ukrotili tisto, kar je trenutno mešanica standardov zastopanja za iste informacije, in sicer z zagotavljanjem standardnega načina pretvarjanja med zapuščeno predstavitvijo - naj bo to macintoška grščina ali Windows cirilica - in Unicode. Torej se razredu Java, ki se ukvarja z nizi, ni treba spreminjati, ko se premika od platforme do platforme. To je lahko konec zgodbe, le da se zdaj, ko je pretvorbena koda zaprta, postavlja vprašanje, kaj ta koda predpostavlja.

Med raziskovanjem te kolumne sem se spomnil slavnega citata direktorja Xeroxa (prej je bil Xerox, ko je bilo podjetje Haloid), da je fotokopirni stroj odveč, ker je bilo tajniku dokaj enostavno vstaviti košček karbonskega papirja pisalnega stroja in naredite kopijo dokumenta, ko je ustvarjala izvirnik. Seveda je v ozadju očitno, da fotokopirni stroj osebi, ki prejme dokument, koristi veliko bolj kot osebi, ki dokument ustvarja. JavaSoft je pokazal podobno pomanjkanje vpogleda v uporabo razredov kodiranja in dekodiranja znakov pri njihovi zasnovi tega dela sistema.

$config[zx-auto] not found$config[zx-overlay] not found