Dubinski uvid u tip Java znaka

Verzija Java 1.1 uvodi brojne klase za bavljenje likovima. Te nove klase stvaraju apstrakciju za pretvaranje iz pojma vrijednosti znakova specifičnih za platformu u vrijednosti Unicodea . Ovaj stupac razmatra što je dodano i motivacije za dodavanje ovih klasa znakova.

Upišite char

Možda najviše zlorabljeni osnovni tip u C jeziku je tip char . Vrsta char djelomično se zlostavlja jer je definirana kao 8 bitova, a tijekom posljednjih 25 godina 8 bitova definira i najmanji nedjeljivi komad memorije na računalima. Kada kombinirate potonju činjenicu s činjenicom da je ASCII skup znakova definiran da stane u 7 bitova, tip char čini vrlo prikladan "univerzalni" tip. Dalje, u C-u je pokazivač na varijablu tipa char postao univerzalni tip pokazivača jer se na sve što se može označiti kao char može upotrijebiti i na bilo koji drugi tip upotrebom lijevanja.

Upotreba i zloupotreba tipa char u jeziku C dovela je do mnogih nekompatibilnosti između implementacija kompajlera, pa su u ANSI standardu za C izvršene dvije specifične promjene: Univerzalni pokazivač redefiniran je tako da ima vrstu praznine, što zahtijeva izričitu izjava programera; a numerička vrijednost znakova smatrala se potpisanom, definirajući na taj način kako će se postupati s njima kada se koriste u numeričkim proračunima. Tada su sredinom 1980-ih inženjeri i korisnici shvatili da je 8 bitova nedovoljno za predstavljanje svih likova na svijetu. Nažalost, do tada je C bio toliko ukorijenjen da ljudi nisu bili voljni, možda čak i nesposobni, promijeniti definiciju znakatip. Sada bljesnite naprijed u '90 -te, u rane početke Jave. Jedan od mnogih principa postavljenih u dizajnu jezika Java bio je da znakovi budu 16 bita. Ovaj izbor podržava upotrebu Unicode-a , standardnog načina predstavljanja različitih vrsta znakova na mnogo različitih jezika. Nažalost, to je također postavilo povod za niz problema koji se tek sada otklanjaju.

Što je uopće lik?

Znao sam da imam problema, kad sam se zapitao: "Pa što je lik?" Pa, lik je slovo, zar ne? Hrpa slova čini riječ, riječi tvore rečenice itd. Stvarnost je, međutim, da odnos između predstavljanja lika na računalnom ekranu, koji se naziva njegov glif , i numeričke vrijednosti koja određuje da glif, nazvan a code point, zapravo uopće nije jednostavan.

Smatram se sretnim što sam izvorni govornik engleskog jezika. Prvo, jer je to bio zajednički jezik značajnog broja onih koji su pridonijeli dizajnu i razvoju suvremenog digitalnog računala; drugo, jer ima relativno mali broj glifa. U ASCII definiciji postoji 96 znakova za ispis koji se mogu koristiti za pisanje engleskog jezika. Usporedite to s kineskim, gdje je definirano preko 20 000 glifa, a ta je definicija nepotpuna. Od ranih početaka u Morseovom i Baudotovom kodu, ukupna jednostavnost (malo glifa, statistička učestalost pojavljivanja) engleskog jezika učinila ga je lingua-francom digitalnog doba. No kako se povećavao broj ljudi koji ulaze u digitalno doba, tako se povećavao i broj stranih govornika engleskog jezika. Kako su brojevi rasli,sve je više ljudi bilo sve nesklonije prihvaćati da računala koriste ASCII i govore samo engleski. To je uvelike povećalo broj računala s "znakovima" koji su trebali biti razumljivi. Kao rezultat, broj glifa kodiranih od računala morao se udvostručiti.

Broj dostupnih znakova udvostručio se kada je časni 7-bitni ASCII kôd ugrađen u 8-bitno kodiranje znakova pod nazivom ISO Latin-1 (ili ISO 8859_1, a "ISO" je Međunarodna organizacija za standarde). Kao što ste možda shvatili pod nazivom kodiranja, ovaj je standard omogućio predstavljanje mnogih jezika izvedenih iz latinice koji se koriste na europskom kontinentu. Samo zato što je standard stvoren, nije značilo da je i upotrebljiv. U to je vrijeme mnoštvo računala već počelo koristiti ostalih 128 "znakova" koje bi u neku prednost mogao predstavljati 8-bitni znak. Dva preživjela primjera upotrebe ovih dodatnih znakova su IBM osobno računalo (PC) i najpopularniji računalni terminal ikad, Digital Equipment Corporation VT-100.Potonji živi u obliku softvera emulatora terminala.

O stvarnom vremenu smrti 8-bitnog lika nesporno će se raspravljati desetljećima, ali ja ga pripisujem uvođenju Macintosh računala 1984. Macintosh je donio dva vrlo revolucionarna koncepta u uobičajeno računanje: fontovi znakova koji su bili pohranjeni u RADNA MEMORIJA; i WorldScript koji se mogu koristiti za predstavljanje znakova na bilo kojem jeziku. Naravno, ovo je bila jednostavno kopija onoga što je Xerox isporučivao na svojim strojevima klase maslačak u obliku sustava za obradu riječi Star, ali Macintosh je te nove skupove znakova i fontove donio publici koja je još uvijek koristila "glupe" terminale . Jednom započeta upotreba različitih fontova nije se mogla zaustaviti - bila je previše privlačna previše ljudi. Krajem 80-ih,pritisak na standardizaciju upotrebe svih ovih znakova došao je na vrh usponom konzorcija Unicode, koji je objavio svoju prvu specifikaciju 1990. Nažalost, tijekom 80-ih, pa čak i do 90-ih, broj skupova znakova se umnožio. Veoma je malo inženjera koji su u to vrijeme stvarali nove znakovne kodove smatrali da je novonastali Unicode standard održiv, pa su stvorili vlastita mapiranja kodova na glifove. Dakle, iako Unicode nije bio dobro prihvaćen, ideja da postoji samo 128 ili najviše 256 znakova definitivno je nestala. Nakon Macintosha, podrška za različite fontove postala je nužna značajka za obradu teksta. Osam bitnih likova nestajalo je.80-ih, pa čak i u 90-te, broj setova znakova umnožio se. Veoma je malo inženjera koji su u to vrijeme stvarali nove znakovne kodove smatrali da je novonastali Unicode standard održiv, pa su stvorili vlastita mapiranja kodova na glifove. Dakle, iako Unicode nije bio dobro prihvaćen, ideja da postoji samo 128 ili najviše 256 znakova definitivno je nestala. Nakon Macintosha, podrška za različite fontove postala je nužna značajka za obradu teksta. Osam bitnih likova nestajalo je.80-ih, pa čak i u 90-te, broj setova znakova umnožio se. Veoma je malo inženjera koji su u to vrijeme stvarali nove znakovne kodove smatrali da je novonastali Unicode standard održiv, pa su stvorili vlastita mapiranja kodova na glifove. Dakle, iako Unicode nije bio dobro prihvaćen, ideja da postoji samo 128 ili najviše 256 znakova definitivno je nestala. Nakon Macintosha, podrška za različite fontove postala je nužna značajka za obradu teksta. Osam bitnih likova nestajalo je.ideja da je na raspolaganju bilo samo 128 ili najviše 256 znakova definitivno je nestala. Nakon Macintosha, podrška za različite fontove postala je nužna značajka za obradu teksta. Osam bitnih likova nestajalo je.ideja da je na raspolaganju bilo samo 128 ili najviše 256 znakova definitivno je nestala. Nakon Macintosha, podrška za različite fontove postala je nužna značajka za obradu teksta. Osam bitnih likova nestajalo je.

Java i Unicode

U priču sam ušao 1992. godine kada sam se pridružio grupi Hrast (jezik Java zvao se Hrast kad je prvi put razvijen) u tvrtki Sun. Osnovni tip chardefinirano je kao 16 nepotpisanih bitova, jedini nepotpisani tip u Javi. Obrazloženje 16-bitnog znaka bilo je da će podržavati bilo koji prikaz Unicode znakova, čineći tako Javu prikladnom za predstavljanje nizova na bilo kojem jeziku koji podržava Unicode. Ali mogućnost predstavljanja niza i mogućnosti ispisa uvijek su bili zasebni problemi. S obzirom na to da je većina iskustva u hrastovoj grupi dolazila iz Unix sustava i sustava izvedenih iz Unixa, najudobniji skup znakova bio je, opet, ISO Latin-1. Također, s Unixovim nasljeđem grupe, Java I / O sustav modeliran je velikim dijelom na Unix apstrakciji toka, pri čemu bi svaki I / O uređaj mogao biti predstavljen strujom od 8-bitnih bajtova. Ova kombinacija ostavila je pogrešku u jeziku između 8-bitnog uređaja za unos i 16-bitnih znakova Java. Tako,bilo gdje iz Java-nizova koji su se trebali čitati ili pisati u 8-bitni tok, postojao je mali kôd, hak, za čarobno mapiranje 8-bitnih znakova u 16-bitni unicode.

U 1.0 verzijama Java Developer Kit (JDK) ulazni hak bio je u DataInputStreamklasi, a izlazni hak cijela PrintStreamklasa. (Zapravo je postojala ulazna klasa imenovana TextInputStreamu alfa 2 izdanju Jave, ali to je zamijenjeno DataInputStreamhakiranjem u stvarnom izdanju.) To nastavlja stvarati probleme početnicima Java programerima, jer očajnički traže Java ekvivalent C funkciju getc(). Razmotrite sljedeći program Java 1.0:

import java.io. *; lažna javna klasa {public static void main (String args []) {FileInputStream fis; DataInputStream dis; char c; isprobajte {fis = new FileInputStream ("data.txt"); dis = novi DataInputStream (fis); while (true) {c = dis.readChar (); System.out.print (c); System.out.flush (); if (c == '\ n') prekid; } fis.close (); } catch (Iznimka e) {} System.exit (0); }}

Na prvi pogled čini se da ovaj program otvara datoteku, čita je jedan po jedan znak i izlazi kad se pročita prva nova linija. Međutim, u praksi dobivate smeće. A razlog zbog kojeg dobivate smeće je taj što readChar čita 16-bitne Unicode znakove i System.out.printispisuje ono što pretpostavlja da su ISO latino-1 8-bitni znakovi. Međutim, ako gornji program promijenite tako da koristi funkciju readLineDataInputStream , čini se da će raditi jer kod u readLinečita format koji je definiran usputnim klimanjem prema Unicode specifikaciji kao "modificirani UTF-8". (UTF-8 je format koji Unicode navodi za predstavljanje Unicode znakova u 8-bitnom ulaznom toku.) Dakle, situacija u Javi 1.0 je da su Java nizovi sastavljeni od 16-bitnih Unicode znakova, ali postoji samo jedno mapiranje koje preslikava ISO latinični znakovi-1 u Unicode. Srećom, Unicode definira kodnu stranicu "0" - odnosno 256 znakova čiji su gornjih 8 bitova nula - kako bi točno odgovarali ISO Latin-1 skupu. Prema tome, mapiranje je prilično trivijalno i dok koristite samo datoteke znakova ISO Latin-1, nećete imati problema kada podaci napuste datoteku, ako njima manipulira Java klasa, a zatim se prepišu u datoteku .

Bila su dva problema sa zakopavanjem ulaznog pretvorbenog koda u ove klase: Nisu sve platforme pohranile svoje višejezične datoteke u modificiranom UTF-8 formatu; i svakako, aplikacije na tim platformama nisu nužno očekivale nelatinične znakove u ovom obliku. Stoga je podrška za implementaciju bila nepotpuna i nije bilo jednostavnog načina za dodavanje potrebne podrške u kasnijem izdanju.

Java 1.1 i Unicode

Izdanje Java 1.1 predstavilo je potpuno novi skup sučelja za rukovanje znakovima, nazvanim Readersi Writers. Izmijenio sam klasu bogusodozgo u klasu s imenom cool. coolKlasa koristi InputStreamReaderklasu za obradu datoteka, a ne na DataInputStreamklasu. Imajte na umu da InputStreamReaderje to podklasa nove Readerklase, a System.outsada je PrintWriterobjekt, što je podklasa Writerklase. Kôd za ovaj primjer prikazan je u nastavku:

import java.io.*; public class cool { public static void main(String args[]) { FileInputStream fis; InputStreamReader irs; char c; try { fis = new FileInputStream("data.txt"); irs = new InputStreamReader(fis); System.out.println("Using encoding : "+irs.getEncoding()); while (true) { c = (char) irs.read(); System.out.print(c); System.out.flush(); if (c == '\n') break; } fis.close(); } catch (Exception e) { } System.exit(0); } } 

The primary difference between this example and the previous code listing is the use of the InputStreamReader class rather than the DataInputStream class. Another way in which this example is different from the previous one is that there is an additional line that prints out the encoding used by the InputStreamReader class.

The important point is that the existing code, once undocumented (and ostensibly unknowable) and embedded inside the implementation of the getChar method of the DataInputStream class, has been removed (actually its use is deprecated; it will be removed in a future release). In the 1.1 version of Java, the mechanism that performs the conversion is now encapsulated in the Reader class. This encapsulation provides a way for the Java class libraries to support many different external representations of non-Latin characters while always using Unicode internally.

Of course, like the original I/O subsystem design, there are symmetric counterparts to the reading classes that perform writing. The class OutputStreamWriter can be used to write strings to an output stream, the class BufferedWriter adds a layer of buffering, and so on.

Trading warts or real progress?

The somewhat lofty goal of the design of the Reader and Writerclasses was to tame what is currently a hodge-podge of representation standards for the same information by providing a standard way of converting back and forth between the legacy representation -- be it Macintosh Greek or Windows Cyrillic -- and Unicode. So, a Java class that deals with strings need not change when it moves from platform to platform. This might be the end of the story, except that now that the conversion code is encapsulated, the question arises as to what that code assumes.

Istražujući ovu kolumnu, podsjetio sam se na čuveni citat izvršnog direktora tvrtke Xerox (prije nego što je to bio Xerox, dok je to bila tvrtka Haloid) kako je fotokopirni uređaj bio suvišan jer je tajniku bilo prilično lako staviti komad karbonskog papira u njezinu pisaću mašinu i napravite kopiju dokumenta dok je stvarala original. Naravno, ono što je očigledno u prošlosti jest da aparat za fotokopiranje koristi osobi koja prima dokument mnogo više nego osobi koja generira dokument. JavaSoft je pokazao sličan nedostatak uvida u upotrebu klasa kodiranja i dekodiranja znakova u njihovom dizajnu ovog dijela sustava.