Konsolda Java Rusça karakterleri. Servlet'lerde Rusça harfler. Rus harfleriyle ilgili sorunları bulmak için algoritma

  • 15.04.2019
Nataşa 26 Ekim 2013, 22:59

Java'daki hata veya özellik: Kiril karakterlerinin konsola çıkışı

  • Java

Yeni başlayan bir programcı olsanız bile Java'da programlama yaparken bilmeniz gereken birçok özellik vardır. Kesit altında size Windows konsolunda Kiril karakterlerinin nasıl görüntüleneceğini anlatacağım ve bunu net bir şekilde göstereceğim.
Basitten başlayalım.

Temel tipler

Java 8'de:

  • boole;
  • bayt, karakter, kısa, int, uzun;
  • yüzer, çift.

karakter- bu karakter türü veri. Bu tür bir değişken, unicode kodlamada saklandığından 2 bayt bellek kaplar.
Bu tür değişkenlerle sadece atama işlemleri yapılabilir, ancak diğer taraftan Farklı yollar... Bunların en basiti şöyle görünür:
c = "b";
Bir sembol, aynı zamanda, içinde yazılı olan kodu şeklinde de temsil edilebilir. sekizli sistem hesaplaşma:
c = "\ 077";
077'nin mutlaka üç basamaklı bir sayı olması durumunda, 377'den (= 255 in ondalık sistem hesaplaşma).
veya içinde onaltılık sistem hesaplaşma Aşağıdaki şekilde:
c = "\ u12a4";
Ek olarak, var Özel semboller, örneğin bir paragraf işareti, sayfa sonu, vb. Bir paragraf işareti, örneğin şöyle yazılacaktır:
c = "\ n";
Bunları burada listelemeye gerek yok. Gerekirse, her zaman referans kitabına bakabilirsiniz.

Şimdi dikkat. Ortam varsayılan kodlaması Java programlama Latince-1'dir. Ancak, System.out akışına çıktı alınırken, karakterler için varsayılan kodlamaya dönüştürülür. işletim sistemi... Bu nedenle, Rusça yerelleştirme için varsayılan kodlama Windows-1251, linux için UTF-8 olacaktır. Ancak, Microsoft tarafından tasarlandığı gibi, karar verdiler. pencere konsolları Cp866 kodlamasını kullanın.

Buna göre, sonuç: doğru görüntü Konsolda kiril karakterleri, Cp866 kodlamasındaki karakterleri göstermeniz gerekiyor!

Bu, aşağıdaki şekilde yapılabilir:

Java.io.PrintStream'i içe aktarın;
java.io.UnsupportedEncodingException'ı içe aktarın;

Herkese açık sınıf Merhaba (
public static void main (String argümanlar) UnsupportedEncodingException oluşturur (/ * Bir UnsupportedEncodingException oluşturulabilir * /
String x = "Merhaba dünya !!!"; // Ekrana yazdıracağımız satır bu
PrintStream printStream = new PrintStream (System.out, true, "cp866");
/ * Oluşturmak yeni akış karakterleri otomatik olarak Cp866 kodlamasına dönüştürecek çıktı * /
printStream.println (x);
}
}
Ortaya çıkan kodu Hello.java dosyasına kaydedelim. Ardından, aşağıdaki içeriğe sahip bir Hello.bat dosyası oluşturalım:
javac Merhaba.java
java -cp. Merhaba
Duraklat
Ve Hello.java dosyasıyla aynı klasöre koyun. Bunun gibi bir şeye benzemeli:

Ardından, ortaya çıkan Hello.bat dosyasını çalıştırın ve işte, aynı dizinde bir Hello.class dosyamız ve "Merhaba, dünya !!!" mesajımız var. Cp866 kodlamasında.

Kodlamanın ne olduğunu bulmak için şu an konsolda kullanıldığında oraya "chcp" yazmanız gerekir. Konsol kodlamasını değiştirmek için "chcp" yazmanız gerekir.<номер кодовой таблицы>"Örneğin" chcp 1251 ". Bu komutun kullanımını göstereceğim:

Not: javac komutunu bulamazsanız, (Windows 7 için) "Bilgisayarım" - "Özellikler" - "Ek sistem parametreleri" - " seçeneklerine gidin. Ortam Değişkenleri"," Sistem Değişkenlerini "bulun ve satırı JDK'nın kurulu olduğu Path değişkenine ekleyin, örneğin" C: \ Program Files \ Java \ jdk1.7.0_25 \ bin "- varsayılan olarak.

Öte yandan, çoğu veri dosyası 8 bitlik karakter gösterimine dayanmaktadır. Buna metin dosyaları ve çoğu veritabanları da dahildir (en gelişmiş olanlar hariç). Ayrıca, kötü olan şey, aynı baytların farklı semboller(kod sayfasına bağlı olarak). Açık bir çelişki var - birinden diğerine nasıl dönüştürüleceği ve bunun tersi ve en az veri kaybıyla. Bunun için kod sayfalarını kullanmak için oldukça uygun bir mekanizma icat edildi. Her kod sayfası için 2 dönüşüm sınıfı oluşturulmuştur (ByteToChar ve CharToByte). Bu sınıflar sun.io paketindedir. Karakterden bayta dönüştürürken karşılık gelen karakter bulunamazsa,? Karakteri ile değiştirilir.

Bu arada, JDK 1.1'in bazı erken sürümlerinde bulunan bu kod sayfası dosyaları hatalar içerir, hatalara neden olmak yürütme sırasında kayıt ve hatta istisnalar. Örneğin, bu KOI8_R kodlaması ile ilgilidir. Bunu yaparken yapılacak en iyi şey, sürümü daha sonraki bir sürümle değiştirmektir. Sun'ın açıklamasına göre, bu sorunların çoğu JDK 1.1.6'da çözülmüştür.

Bu dönüşüm ne zaman ve nasıl kullanılmalıdır? Prensipte ne zaman kullanılacağı açıktır - bayttan karaktere herhangi bir dönüşüm için ve bunun tersi de geçerlidir. String sınıfında, bir dönüşümün olduğu yerlerde, kod sayfasının adını belirten ek bir parametre (String enc) belirtebilirsiniz. Bir bayt dizisi oluşturucusu ve bir getBytes() yöntemidir. Ancak, gerçek bir programda, kod sayfasını açıkça belirtmek her zaman uygun değildir. Bunun için varsayılan bir kodlama tanıtıldı. Varsayılan olarak, sisteme bağlıdır (Rus Windows için Cp1251 kodlaması kabul edilir) ve eski JDK'larda file.encoding sistem özelliği ayarlanarak değiştirilebilir. Aslında Sun'ın belirttiği gibi, bu özellik sistem kodlamasını yansıtır ve komut satırında değiştirilmemelidir (örneğin, BugID'deki yorumlara bakınız).Bu kodlama, sayfa adı açıkça belirtilmediğinde kullanılır. Çünkü bu ayar tüm dönüşümler için aynıdır, bazen sorun yaşayabilirsiniz. Örneğin, Windows söz konusu olduğunda genellikle kabul edilemez olan konsol ekranına görüntülemek için aynı ayar kullanılır - orada Cp866 sayfasını kullanmanız gerekir. Bu kodlamalar bağımsız olarak belirtilseydi harika olurdu - örneğin, console.encoding, vb., ancak Sun-sheep'in henüz bu kadar önemli konulara girmediğini düşünüyorum.

Bu arada, konsolun çıktısı hakkında. Yukarıdaki sorunu çözmenin iki yolu vardır:

  1. System.out.println yerine kendi sınıfınızı kullanın ve ardından dönüştürmeyi bunun içinde yapın. Örneğin:
    genel sınıf Msg (statik Dize cp = System.getProperty ("console.encoding", "Cp866"); genel statik geçersiz ileti (Dize msg) (msg + = "\ n"; bayt b; deneyin (b = msg.getBytes) (cp);) catch (UnsupportedEncodingException e) (// Gerekli kodlama yoksa, // varsayılan dönüştürmeyi yapın b = msg.getBytes ();) System.out.write (b);)) ... Msg .mesaj ("Mesaj");
  2. İstediğiniz kodlamayı destekleyen kendi PrintStream sürümünüzü yazın ve System.setOut () ve System.setErr () aracılığıyla değiştirin. Örneğin, programlarımdaki olağan başlangıç ​​şudur:
    ... public static void main (String args) (// Konsol mesajlarının çıktısının ayarlanması // gerekli kodlama denemesinde (System.setOut (yeni CodepagePrintStream (System.out, System.getProperty ("console.encoding", ") Cp866") ));) catch (UnsupportedEncodingException e) (System.out.println ("Konsol kod sayfası kurulamıyor:" + e);) ...

fakir nereye gidilir Rus programcı? Umutsuzluğa kapılmayın, ihtiyacınız olan kodlamada dosyalardan veri okumanın ve kaydetmenin birçok yolu vardır.

  1. Bayt (bayt) dizilerini okuyun ve yazın ve dönüştürmek için String sınıfının belirtilen yöntemlerini kullanın. Bu yöntem, akış farklı kodlamalarda veri içerebildiğinde özellikle uygundur.
  2. Java.io paketinden bu amaç için özel olarak tasarlanmış InputStreamReader ve OutputStreamWriter sınıflarını kullanın.
  3. İstenen kodlamaya dönüştürmeyi yapın. Her şeyi doğru yaparsanız, veriler kaybolmaz, ancak elbette bunu yalnızca son çare olarak kullanmanız önerilir. Örnek:
    // Sadece Cp437'yi destekleyen bir nesne üzerinden kodlama yapan Cp866'daki Rusça harfleri okuma // Cp437 String str = o.readString (); str = new String (str.getBytes ("Cp437"), "Cp866"); // Rusça harfleri kaydetme // sadece Cp437'yi destekleyen bir nesne aracılığıyla kodlamayı Cp866'ya // kaydetme str = new String (str.getBytes ("Cp866"), "Cp437"); o.writeString (str);
    Bu yöntem ve bununla ilgili olası sorunlar hakkında daha fazla ayrıntı, aşağıda Karakter dönüştürme yöntemi hakkında bölümünde açıklanmıştır.
  4. Gerekli kodlama için veritabanı sürücüsünü yapılandırın. Tam olarak nasıl belirli sürücüye bağlıdır. Ne yazık ki, birçok sürücünün oradaki herhangi bir kodlama hakkında hiçbir fikri yoktur. Bazen bu hesapta yama yapılabilir, ancak daha sıklıkla dolambaçlı yollarla hareket etmeniz gerekir.

    Örneğin, en sık kullanılan sürücülerden biri JDBC-ODBC köprüsüdür. JDK 1.1 sürümlerinde, bu köprü, önceki paragrafta açıklananlar gibi ek ince ayarlar gerektiren karakter kodlamalarını görmezden geldi (bu aynı zamanda en son sürümleri olan 1.1.8 için de geçerlidir).

    Sun Java 2 köprüsü artık istenen kodlama için yapılandırılabilir. Bu ekleyerek yapılır ek mülk charSet, tabana bir bağlantı açmak için geçirilen bir dizi parametreye. Varsayılan dosya.encoding'dir. Bu böyle bir şey yapılır:

    // Tabana bağlanma parametreleri Özellikler connInfo = new Properties (); connInfo.put ("kullanıcı", kullanıcı adı); connInfo.put ("şifre", şifre); connInfo.put ("charSet", "Cp1251"); // Bağlantı kurun Bağlantı db = DriverManager.getConnection (dataurl, connInfo);

    Başka bir örnek, Linux altında Oracle 8.0.5'ten JDBC-OCI sürücüsüdür (saf Java değil - buna ince denir). Veritabanından veri alırken, sürücü "kendi" kodlamasını NLS_LANG ortam değişkenini kullanarak belirler. Bu değişken bulunamazsa, kodlamanın ISO88591 olduğunu varsayar. İşin püf noktası, NLS_LANG'nin tam olarak bir ortam değişkeni olması gerektiği ve özelliklerin (file.encoding gibi) burada "yuvarlanmadığı". Sürücünün Apache + Jserv sunucu uygulaması motoru içinde kullanılması durumunda, Çevre değişkeni jserv.properties dosyasında ayarlanabilir:

    wrapper.env = NLS_LANG = American_America.CL8KOI8R
    Bununla ilgili bilgiler, kendisine özel olarak teşekkür edilen Sergei Bezrukov tarafından gönderildi.

Formatı oluşturmakta özgürseniz, o zaman her şey daha kolaydır. Unicode veya UTF8 kullanın ve sorun olmayacaktır.

Bir veritabanı söz konusu olduğunda, elbette, bir tür onaltılık biçim kullanabilirsiniz, ancak bu her zaman kabul edilebilir değildir, çünkü 2 - 4 kat daha fazla disk alanı elde edecek ve kullanma yeteneğinizi kaybedeceksiniz. standart programlar bir veritabanı ile çalışın, örneğin rapor oluşturucular.

Belirtildiği gibi, program yürütülürken Unicode kullanır. Kaynak dosyalar sıradan editörlerde yazılır. Far kullanıyorum, muhtemelen favori editörünüz var. Bu düzenleyiciler, dosyaları 8 bit biçiminde kaydeder; bu, yukarıdakine benzer bir mantık yürütmenin bu dosyalar için de geçerli olduğu anlamına gelir. Farklı derleyici sürümleri, karakter dönüştürmeyi biraz farklı şekilde gerçekleştirir. JDK 1.1.x'in önceki sürümleri, standart olmayan -J seçeneğiyle geçersiz kılınabilen file.encoding ayarını kullanır. Daha yenilerinde (Denis Kokarev tarafından bildirildiği gibi - 1.1.4'ten beri) ek parametre- kullanılan kodlamayı belirtebileceğiniz kodlama. Derlenmiş sınıflarda, dizeler Unicode biçiminde (daha doğrusu UTF8 biçiminin değiştirilmiş bir sürümünde) temsil edilir, bu nedenle en ilginç şey derleme sırasında olur. Bu nedenle en önemli şey kaynak kodlarınızı hangi kodda kodladığını bulmak ve derlerken doğru değeri belirtmektir. Varsayılan olarak, aynı kötü şöhretli file.encoding kullanılacaktır. Derleyiciyi çağırmaya bir örnek:

Bu ayarı kullanmaya ek olarak, bir yöntem daha vardır - karakter kodunun belirtildiği "\ uxxxx" biçiminde harfleri belirtmek için. Bu yöntem tüm sürümlerde çalışır ve bu kodları almak için kullanabilirsiniz. standart yardımcı program native2ascii.

Özelliklerde Rus harfleri.

Kaynak yükleme yöntemleri, belirli bir şekilde çalışan özellik dosyalarını okumak için kullanılır. Aslında, okuma için, file.encoding'i kullanmayan (kodlama orada sabit kodlanmıştır) Properties.load yöntemi kullanılır, bu nedenle tek yol Rusça harfleri belirtin - "\ uxxxx" biçimini ve native2ascii yardımcı programını kullanın.

Properties.save yöntemi, JDK 1.1 ve 1.2'de farklı şekilde çalışır. 1.1 sürümlerinde, yalnızca yüksek baytı attı, bu nedenle yalnızca İngilizce harflerle doğru çalıştı. 1.2, "\ uxxxx"e ters dönüştürme yapar, bu nedenle yükleme yöntemine yansıtılmış olarak çalışır.

Servlet'lerde Rusça harfler.

Peki, aynı Servlet'lerin ne işe yaradığını, sanırım biliyorsunuz. Değilse, önce belgeleri okumak en iyisidir. Burada sadece Rus harfleriyle çalışmanın özellikleri açıklanmaktadır.

Peki özellikleri nelerdir? Servlet istemciye bir yanıt gönderdiğinde, bu yanıtı göndermenin iki yolu vardır - bir OutputStream (getOutputStream()) veya bir PrintWriter (getWriter()) aracılığıyla. İlk durumda, bayt dizileri yazarsınız, bu nedenle yukarıdaki bir dosyaya yazma yöntemleri uygulanabilir. PrintWriter durumunda, set kodlamasını kullanır. Her durumda, sunucu tarafında doğru karakter dönüşümü için setContentType() yöntemi çağrılırken kullanılan kodlamayı doğru bir şekilde belirtmelisiniz. Bu yönerge getWriter() çağrılmadan veya OutputStream'e ilk yazılmadan önce yapılmalıdır. Örnek:

public void doPost (HttpServletRequest isteği, HttpServletResponse yanıtı) ServletException, IOException (response.setContentType ("metin / html; karakter kümesi = windows-1251")); PrintWriter çıkışı = yanıt.getWriter(); // Kontrol edilecek kodlama adının çıktısında hata ayıklayın.println ("Encoding:" + response.getCharacterEncoding ()); ... dışarı.kapat ();
Müşteriye cevaplar vermekle ilgili. Ne yazık ki, giriş parametreleriyle o kadar kolay değil. Giriş parametreleri"application / x-www-form-urlencoded" MIME tipine göre tarayıcı tarafından kodlanır. Alexey Mendelev'in dediği gibi, tarayıcılar şu anda ayarlanmış kodlamayı kullanarak Rusça harfleri kodlar. Ve elbette, onun hakkında hiçbir şey rapor edilmedi. Buna göre örneğin JSDK 2.0 ve 2.1'de bu hiçbir şekilde kontrol edilmez. Aslında, kod çözme için, yalnızca yüksek baytı sıfırlayan HttpUtils.parsePostData () ve HttpUtils.parseQueryString () yöntemleri kullanılır. Bu, JSDK'da () kayıtlı bir hatadır. Ne yazık ki bu hata "Düzelmeyecek" olarak kapatıldı, bahanesiyle RFC'de bu konu hakkında hiçbir şey söylenmediği için hiçbir şey yapmayacağız. Ancak geliştiricilerimizin SERVLET-INTEREST mail listesindeki yazışmalarından sonra konu çığırından çıkmış görünüyor. En azından sözlü olarak, JSDK 2.3 belirtiminde kodlamayı ayarlamak için bir yöntemin dahil edileceğine söz verildi.

Bu arada kendi imkanlarımızla idare etmemiz gerekiyor. orijinal yol kodlamalarla çalışma, Rus Apache tarafından sunulmaktadır - tam olarak nasıl olduğu açıklanmıştır. İncelemelere bakıldığında, Reçine sisteminin Ruslarla da hiçbir sorunu yok.

JNI (Java Native Interface), C/C++ koduyla birlikte çalışmak için bir standarttır. Tahmin edebileceğiniz gibi, bu dönüm noktasında 8-bit ve 16-bit kodlamaların çarpışması da var. Çoğu C/C++ programı Unicode düşünülmeden yazılmıştır, çoğu programcı bunu bilmez bile. Ben kendim, C / C ++ ile 7 yıl boyunca Java'da yazmaya başlayana kadar Unicode'u yalnızca kulaktan dolma bilgilerle biliyordum. C / C++'daki string işlemlerinin çoğu 8 bitlik C tipi char için yapılır. Prensip olarak, bu yönde bir miktar ilerleme vardır, özellikle Windows NT için Win32 API'sinin Unicode varyantlarıyla etkileşime girecek kodu derlemek mümkündür, ancak ne yazık ki bu genellikle yeterli değildir.

Bu nedenle asıl görev, jstring türünden (JNI-shnoe String eşleme) char * türünü almak ve bunun tersidir. Hemen hemen tüm JNI açıklamaları ve örnekleri, bunun için bir çift GetStringUTFChars / ReleaseStringUTFChars işlevi kullanır. Kurnaz burjuvazi burada da bir pusu hazırladı - bu işlevler, yalnızca ASCII karakterleri (ilk 128 değer) için beklenene karşılık gelen UTF standardına göre bir bayt dizisi oluşturur. Rus harfleri tekrar uçuşta. Cic char, Java bayt türüyle çok iyi uyum sağlar, ancak boş karakter biçiminde bir yakalama vardır. bayt-> char * dönüştürülürken eklenmeli ve ters dönüşüm... Bunu C/C++'da yapmak elverişsizdir, bu yüzden yapılacak en iyi şey Java'da mümkün olan maksimumu yapmaktır. Örnek:

// sish dizesini al public static byte getCString (String s) (return (s + "\ 0"). GetBytes ();) public void eylemi (String msg) Java.io.IOException (int res = nAction (getCString) atar (msg )); if (res! = 0) yeni Java.io.IOException (getErrorString (res));) özel String getErrorString (int error) (byte buf = yeni bayt; int len ​​​​= nGetErrorString (hata, buf); yeni Dize döndür (buf, 0, len);) özel yerel int nAction (bayt msg); özel yerel int nGetErrorString (int hatası, bayt iletisi); ... JNIEXPORT jint JNICALL Java_Test_nAction (JNIEnv * env, jobject nesnesi, jbyteArray msg) (jint res; jbyte * bmsg = (* env) -> GetByteArrayElements (env, msg, NULL); printf (bmsgomething); res = do_ ); (* env) -> ReleaseByteArrayElements (env, msg, bmsg, JNI_ABORT); res dön;) JNIEXPORT jint JNICALL Java_Test_nGetErrorString (JNIEnv * env, jobject nesnesi, jint hatası, jbyteArte, msvBmsE, msvBmsE (msvBmsE) -> NULL); jsize sz = (* env) -> GetArrayLength (env, msg); jint len; get_error_string (hata, bmsg, sz); len = strlen (bmsg); (* env ) -> ReleaseByteArrayElements (env, msg, bmsg, 0); dönüş len;)
Sistem API'si ile etkileşime girerken oldukça doğal olan varsayılan karakter dönüşümü burada kullanılır. Belirli bir kod sayfasına ihtiyacınız varsa, adını buna göre eklemeniz gerekir.

GUI (AWT, Salıncak)

Birçok kişi, Rusça harflerin yanlış görüntülenmesini, yazı tipinin yanlış yüklenmesiyle ilişkilendirir. Bana öyle geliyor ki bu, asıl nedenin gerçekten bu olduğu Windows 3.x'teki zorlu programlama deneyiminden kaynaklanıyor. Java'da işler daha karmaşıktır ve yazı tipleriyle nadiren ilişkilidir. Tarayıcıların belirli ayarlarını anlamadım, çünkü Henüz applet yazmadım, sadece aplikasyonlar yazdım ama son sürümlerde bu konuda her şeyin yolunda olduğunu düşünüyorum.

en büyük nerede sualtı kayaları? Bu, esas olarak yanlış karakter dönüşümünden kaynaklanmaktadır. Bu sorunlardan bazıları ve bunları çözme yöntemleri yukarıda açıklanmıştır. Tüm dönüştürmeleri doğru bir şekilde gerçekleştirdiyseniz ve çıktı bir Unicode yazı tipi kullanıyorsa, programınızın doğru çalışma olasılığı çok yüksektir.

Sorunlar hala devam ediyorsa, nerede ortaya çıktıklarını bulmanız gerekir. Uygulamanızı farklı JVM'ler altında çalıştırmayı deneyin. farklı platformlar, farklı tarayıcılarda.

Program hiçbir yerde çalışmıyorsa, sorun yalnızca onda ve sizin elinizdedir. Yukarıda yazılanları dikkatlice tekrar okuyun ve bakın. Sorun yalnızca belirli bir ortamda kendini gösteriyorsa, sorun büyük olasılıkla ayarlardadır. Tam olarak nerede, hangi grafik kitaplığını kullandığınıza bağlıdır. AWT - yardımcı olabilir doğru ayar font.properties.ru dosyası. Örnek doğru dosya Java 2'den alınabilir. Bu sürüme sahip değilseniz, bu siteden indirebilirsiniz: Windows için sürüm, Linux için sürüm. İşletim sisteminin Rusça sürümü yüklüyse, bu dosyayı font.properties dosyasının bulunduğu yere eklemeniz yeterlidir. Bu İngilizce sürümse, -Duser.language = ru ayarını ayarlayarak mevcut dili ek olarak değiştirmeniz veya font.properties yerine bu dosyayı yeniden yazmanız gerekir. Bu dosya, kullanılacak yazı tiplerini ve kod sayfalarını belirtir.

Swing kitaplığı ile her şey daha basittir - her şey Java2D alt sistemi aracılığıyla çizilir. Standart iletişim kutularındaki (JOptionPane, JFileChooser, JColorChooser) etiketleri Rusça'ya dönüştürmek çok kolaydır - sadece birkaç kaynak dosyası oluşturmanız yeterlidir. Bunu zaten yaptım, böylece bitmiş dosyayı alıp CLASSPATH'inize ekleyebilirsiniz. Karşılaştığım tek sorun, 1.2 rc1 ve 1.3 beta'dan başlayan JDK sürümlerinde, kullanırken Win9x altında Rusça harflerin görüntülenmemesi. standart yazı tipleri(Arial, Courier New, Times New Roman, vb.) Java2D'deki bir hata nedeniyle. Hata oldukça tuhaf - standart yazı tiplerinde harf görüntüleri Unicode kodlarına göre değil, Cp1251 tablosuna (Ansi kodlaması) göre görüntülenir. Bu hata, BugParade'de numaranın altında kayıtlıdır. Varsayılan olarak Swing, font.properties.ru dosyasında belirtilen yazı tiplerini kullanır, bu nedenle bunları başkalarıyla değiştirmek yeterlidir ve Rusça harfler görünecektir. Ne yazık ki, çalışan yazı tipleri grubu küçüktür - bunlar Tahoma, Tahoma Bold yazı tipleri ve JDK dağıtımından iki yazı tipi grubudur - Lucida Sans * ve Lucida Typewriter * (font.properties.ru dosyası örneği). Bu yazı tiplerinin standart olanlardan nasıl farklı olduğu benim için net değil.

1.3rc1 sürümünden başlayarak bu sorun zaten çözülmüştür, böylece JDK'yı kolayca güncelleyebilirsiniz. Win95'in orijinal sürümünün Unicode'u desteklemeyen yazı tipleriyle birlikte geldiğine de dikkat edilmelidir - bu durumda yazı tiplerini Win98 veya WinNT'den kopyalayabilirsiniz.

Eğer burun kanamanız varsa, JDK 1.2'de çalışırken standart yazı tiplerini kullanmanız gerekiyorsa, çıktıdan hemen önce metin satırlarını yeniden kodlayarak bu aksaklığı telafi edebilirsiniz. Bu, örneğin şöyle yapılabilir:

public static String convertToWin9x (String s) (byte bb; try (bb = s.getBytes ("Cp1251"));) catch (java.io.UnsupportedEncodingException e) (dönüş s;) char cb = new char; for (int i = 0; ben< bb.length; i++) { cb[i] = (char)(bb[i] & 0x00FF); } return new String(cb); }
Ama unutmayın - bu kod işe yarayacaktır. bir tek Win9x ve Sun JDK / JRE 1.2 altında.

Jiklelerle ilgili. Java konferansında (fido7.ru.java) bana söylendiği gibi, bu derleyiciyi kullanırken Rusça harfler de çıkıyor. Bu aslında bir aksaklığın diğerini nasıl telafi ettiğinin klasik bir örneğidir - jikes basitçe kaynak kodlamasını hesaba katmaz. Aynı etki, -encoding anahtarında javac'a kodlama yapan ISO-8859-1 (Latin1) belirtilerek de elde edilebilir. Aynı zamanda, kaynak kodundaki Rusça karakterler Cp1251 kodlamasında yazılırsa, 0x400-0x4ff aralığı (Kiril alfabesi için standart Unicode aralığı) yerine 0x80-0xff aralığına girerler. Win9x ortamında yukarıda bahsedilen aksaklık nedeniyle, standart yazı tiplerinde Kiril sadece bu aralıkta görüntülenir ve Rusça harfler görünür. Programı başka bir ortamda (örneğin, WinNT'de) çalıştırmayı denerseniz, bu aksaklık orada olmadığı için Rusça harfler olmayacaktır.

Benzer şekilde, bölgesel ayarları Rusça'dan burjuvaya çevirirseniz böyle bir tazminatla karşılaşabilirsiniz. Bu durumda, diğer şeylerin yanı sıra, varsayılan kodlama (file.encoding) de değişir - 1251 yerine 1252 olur. Bu, dosyaları okurken kodlamanın açıkça belirtilmediği (ve -encoding anahtarının olmadığı) gerçeğine yol açar. derleme sırasında belirtilen), ardından Rusça harfler 0x80-0xff aralığına hareket eder ve izlenimi verir normal iş... Java.text.Collator aracılığıyla dönüştürme ve harmanlama durumunda fark görülebilir - bunlar düzgün çalışmayacaktır. Ve eğer string sabitleri kullanıldıysa, diğer platformlarda sadece krakozyabli göreceksiniz.

Başka bir yol, JDK 1.1 için Swing sürümünü indirmek ve uygulamayı Microsoft JVM'nin altından çalıştırmaktır - orada her şey doğru şekilde görüntülenir. MS JVM'nizi güncellemeyi unutmayın - IE 4.x ile gelen sürümler tam olarak düzgün çalışmıyor. En son sürümü Microsoft sunucusundan indirebilirsiniz, örneğin 5.00.3240 - her şey yolunda.

Bu arada, MS JVM hakkında. Hangi nedenlerle olduğu belli değil, ancak Rus harflerini kodlamak için tüm dosyalardan yoksun, acrome Cp1251 (muhtemelen dağılımın boyutunu bu şekilde azaltmaya çalıştılar). Başka kodlamalara ihtiyacınız varsa, örneğin Cp866, o zaman ilgili sınıfları CLASSPATH'e eklemeniz gerekir. Ayrıca, Sun JDK'nın en son sürümlerinden gelen sınıflar uymuyor - Sun yapılarını uzun süredir değiştirdi, bu nedenle en son sürümler Microsoft ile sınıflar eşleşmiyor (MS, JDK 1.1.4'ten bir yapıya sahiptir). Microsoft sunucusunda, prensip olarak, eksiksiz bir ek kodlama seti vardır (sayfa, "Ek G / Ç kitaplıkları" bağlantısı), ancak yaklaşık 3 metre boyutunda bir dosya var ve sunucuları özgeçmişi desteklemiyor :-) . Bu dosyayı indirmeyi başardım, jar ile yeniden paketledim, buradan alabilirsiniz.

I18n (sayıları, tarihleri ​​vb. görüntüler)

Gizemli kombinasyon i18n, basitçe, güçlü Uluslararasılaşma kelimesinin kısaltmasıdır. 18, i ile n arasındaki harf sayısıdır. Bu, Java bağlamında, programı mevcut dile ve ülke özelliklerine göre otomatik olarak ayarlama yeteneği anlamına gelir. Bu, dili temsil eden Locale sınıfı kullanılarak yapılır ve belirli ülke, ve o Yerel Ayarla ne yapacağını bilen sınıflar. Bu sınıfların çoğu java.text paketindedir.

Diğer herkesin kullandığı ana sınıf, yüklemenize izin veren Java.util.ResourceBundle'dır. Farklı çeşit Kaynaklar. Ayrıca, yüklenen sınıfın adı veya özellikler dosyası belirtilen Yerel Ayar'a (veya hiçbir şey belirtilmemişse varsayılan Yerel Ayar'a) bağlıdır.

Aranan dosyanın adı, kaynak adına dil ve ülke tanımlayıcısı eklenerek oluşturulur. Örneğin, yeniden dosya kaynağı yüklenmişse ve geçerli Yerel Ayar ru_RU ise, araması aşağıdaki sırayla yapılacaktır:

  1. resfile_ru_RU.class
  2. resfile_ru_RU.properties
  3. resfile_ru.class
  4. resfile_ru.properties
  5. resfile.class
  6. resfile.properties

Bu, yeni diller ve ülkeler için açıklamalar eklemeyi kolaylaştırır. Sınıfların çoğu, tüm bu dahili mutfağı kendileri hallediyor, bu yüzden çoğu zaman bunu bilmenize gerek yok.

Tarihler için asıl biçimlendirme DateFormat sınıfı tarafından yapılır. getDateInstance(), getTimeInstance() ve getDateTimeInstance() yöntemlerini kullanarak dil ve ülke için önceden yapılandırılmış biçimi alabilirsiniz. Argüman olarak, gerekli biçim stilini belirtmek için sabitlerden birini belirtebilirsiniz. Varsayılan olarak, verilen Yerel Ayar için tercih edilen stil kullanılacaktır. Geçerli sabitler:

Örnek:
// Geçerli tarihi kullanıcıya göster DateFormat df = DateFormat.getDateInstance (); Dize s = df.format (yeni Tarih ()); ... // Geçerli saati saniye olmadan göster DateFormat df = DateFormat. getTimeInstance (DateFormat.KISA); Dize s = df.format (yeni Tarih ());

Görüntülenen alanlar kümesini ve ayırıcılarını kendiniz kontrol etmek istiyorsanız, bunun için SimpleDateFormat sınıfını kullanabilirsiniz.

Sayı biçimlendirme benzer şekilde yapılır. NumberFormat sınıfı bundan sorumludur. getInstance(), getNumberInstance(), getCurrencyInstance() ve getPercentInstance() yöntemlerini kullanarak biçimleri alabilirsiniz. DecimalFormat sınıfını kullanarak kendi formatınızı oluşturabilirsiniz.

native2ascii yardımcı programı hakkında

Bu yardımcı program Sun JDK'nın bir parçasıdır ve kaynak kodunu ASCII biçimine dönüştürmek için tasarlanmıştır. Bu yardımcı program, parametresiz çalıştırıldığında, standart giriş(stdin) ve diğer yardımcı programlar gibi önemli ipuçlarını görüntülemez. Bu, birçoğunun parametreleri belirtmenin gerekli olduğunu bile anlamamasına neden olur (belki de belgelere bakma gücünü ve cesaretini bulanlar hariç :-). Bu arada, bu yardımcı program için doğru iş en azından kullanılan kodlamayı ( -encoding anahtarı) belirtmelisiniz. Bu yapılmazsa, beklenenden biraz farklı olabilecek varsayılan kodlama (file.encoding) kullanılacaktır. Sonuç olarak, yanlış harf kodları aldığınızda (yanlış kodlama nedeniyle), kesinlikle doğru bir kodda hata aramak için çok zaman harcayabilirsiniz.

Karakter dönüştürme yöntemi hakkında

Birçok insan bu yöntemi yanlış kullanır, muhtemelen özünü ve sınırlarını tam olarak anlamaz. Yanlış yorumlanmışlarsa doğru harf kodlarını geri yüklemek için tasarlanmıştır. Yöntemin özü basittir: alınan yanlış karakterlerden uygun kod sayfası kullanılarak orijinal bayt dizisi geri yüklenir. Daha sonra, bu bayt dizisinden, zaten doğru olan sayfa kullanılarak normal karakter kodları elde edilir. Örnek:

String res = new String (src.getBytes ("ISO-8859-1"), "Cp1251");
Bu tekniği kullanırken çeşitli sorunlar olabilir. Örneğin, kurtarma için kullanılır yanlış sayfa veya bazı durumlarda değişebilir. Başka bir sorun, bazı sayfaların belirsiz bir bayt dönüşümü gerçekleştirmesi olabilir.<->karakter. Örneğin, numaraya göre hata açıklamasına bakın.

Bu nedenle, bu yöntemi yalnızca en aşırı durumda, başka hiçbir şey yardımcı olmadığında kullanmaya değer ve karakterlerin yanlış dönüşümünün nerede gerçekleştiği konusunda net bir fikriniz var.
Son değişiklik: 13 Haziran 2000

Sorununuz, Netbeans "konsolunun" - ve işletim sistemi konsolunun - biraz farklı şeyler olmasıdır. Özellikle, kullanılan farklı kodlamalara sahiptirler. Geçerli konsol kodlamasını Konsol API'si aracılığıyla almak en iyisi olacaktır - ancak Java bunu sağlamaz. Bu nedenle konsol kodlaması hakkında farklı bir şekilde bilgi almanız gerekiyor. Örneğin, console.encoding özelliği aracılığıyla.

Yöntem 1

Yeni başlayanlar için, console.encoding özelliğini önceden tanımlanmış bir değere ayarlamak hiçbir şey yapmaz. Bu özellik basitçe kimse tarafından okunamaz. Onu cp866'ya koymak yerine, tam tersine ondan değeri okumalısınız.

Dize kodlaması = System.getProperty ("console.encoding", "utf-8"); Tarayıcı sc = yeni Tarayıcı (System.in, kodlama); PrintStream ps = yeni PrintStream (System.out, kodlama);

Böylece, cp866'da girdi beklemek yerine, program başlatıcının herhangi bir kodlamayı belirlemesine izin verir (utf-8 varsayılan kodlamadır. Bunu NetBeans konsolu tarafından kullanılanla değiştirin). Programı şu şekilde çalıştırmanız gerekecek:

Java -Dconsole.encoding = cp866 ...

İlk bakışta, bu başlatma yöntemi karmaşık görünüyor. Ancak genellikle "ciddi" Java programlarını çalıştırmak için her zaman bazı toplu iş dosyaları kullanılır. Bu anahtarın ona eklenmesini engelleyen nedir?

Ve unutmayın, Windows konsolu herhangi bir kodlamada olabilir! Örneğin, reg.exe gibi bazı programlar yalnızca Windows-1251'de konsolla çalışabilir. Herhangi bir kodlamada çıktı alma yeteneği kullanışlı olabilir.

Chcp 1251 kayıt ... java -Dconsole.encoding = windows-1251 ...

Yöntem 2

Zaten toplu iş dosyalarından bahsediyorsanız, o kadar güçlü olmasa da daha kolay bir yol var. Programı başlatmadan önce konsol kodlamasını istediğiniz kodla değiştirebilirsiniz:

Chcp 1251 java ...

İşte kod numaraları Windows sayfaları bu işe yarayabilir:

  • 866 - cp866
  • 1251 - pencereler-1251
  • 65001 - utf-8 kodlaması
  • 1200 - çift bayt utf-16 kodlaması

not

System.in ve System.out'un genellikle her zaman aynı kodlamada olması gerektiğini unutmayın. senin içinde orijinal program tarayıcı cp866 kodlamasında System.in'den okur - ve yazıcı varsayılan kodlamada System.out'a çıktı verir. Bu tutarsızlık aynı zamanda bir hata kaynağıdır. Bunu asla yapma.

kodlamalar

C'de programlamaya ilk başladığımda, ilk programım (HelloWorld dışında) bir kod dönüştürme programıydı. metin dosyaları ana GOST kodlamasından (bunu hatırlıyor musunuz? :-) alternatif koda. 1991 yılındaydı. O zamandan beri çok şey değişti, ancak ne yazık ki bu tür programlar son 10 yılda alaka düzeyini kaybetmedi. Çeşitli kodlamalarda zaten çok fazla veri birikmiştir ve yalnızca bir tanesiyle çalışabilen çok fazla program kullanılmaktadır. Rus dili için en az bir düzine farklı kodlama var ve bu da sorunu daha da kafa karıştırıcı hale getiriyor.

Tüm bu kodlamalar nereden geldi ve ne için? Bilgisayarlar doğaları gereği sadece sayılarla çalışabilirler. Harfleri bir bilgisayarın belleğinde saklamak için, her harfe belirli bir sayı atamak gerekir (bilgisayarların ortaya çıkmasından önce yaklaşık olarak aynı ilke kullanıldı - aynı Mors kodunu hatırlayın). Ayrıca, sayı arzu edilen şekilde daha küçüktür - daha az ikili basamak kullanılırsa, bellek o kadar verimli kullanılabilir. Karakterler ve sayılar kümesi arasındaki bu yazışma aslında kodlamadır. Ne pahasına olursa olsun hafızadan tasarruf etme arzusu ve ayrılık farklı gruplar bilgisayar bilimcileri ve işlerin mevcut durumuna yol açtı. Şu anda en yaygın kodlama yöntemi, 256'daki toplam karakter sayısını belirleyen bir karakter için bir bayt (8 bit) kullanmaktır. İlk 128 karakter kümesi standartlaştırılmıştır (ASCII kümesi) ve tüm yaygın kodlamalarda aynıdır. (pratik olarak kullanım dışı olmadığı kodlamalar). Anglikan harfleri ve noktalama işaretleri bu aralıktadır, bu da bilgisayar sistemlerinde şaşırtıcı canlılıklarını belirler :-). Diğer diller bu kadar şanslı bir konumda değil - hepsi kalan 128 sayı içinde toplanmak zorunda.

tek kod

1980'lerin sonlarında, çoğu kişi karakter kodlaması için tek bir standart oluşturma ihtiyacını fark etti ve bu da Unicode'un ortaya çıkmasına neden oldu. Unicode, bir kez ve herkes için düzeltme girişimidir belirli numara belirli bir karakterin arkasında. 256 karakterin tüm arzu ile buraya sığmayacağı açıktır. yeterlik uzun zaman 2 bayt (65536 karakter) yeterli gibi görünüyordu. Ama hayır - Unicode standardının (3.1) en son sürümü zaten 94.140 karakter tanımlıyor. Bu kadar çok sayıda karakter için muhtemelen 4 bayt (4294967296 karakter) kullanmanız gerekir. Belki bir süreliğine yeter... :-)

Unicode karakter kümesi, her tür tire ve tire, Yunanca, matematiksel, hiyeroglif, sözde grafik sembolleri vb. ile her türlü harfi içerir. En sevdiğimiz Kiril karakterleri dahil (değer aralığı 0x0400-0x04ff'dir). ). Yani bu tarafta bir ayrımcılık yok.

Belirli karakter kodlarıyla ilgileniyorsanız, bunları görüntülemek için WinNT'nin "Karakter Haritası" programını kullanmak uygundur. Örneğin, burada Kiril aralığı:

Farklı bir işletim sisteminiz varsa veya resmi yorumla ilgileniyorsanız, tüm çizelgeler resmi Unicode web sitesinde (http://www.unicode.org/charts/web.html) bulunabilir.

Karakter ve bayt türleri

Java'da semboller atanır ayrı tip 2 baytlık karakter verileri. Bu genellikle yeni başlayanların kafasında karışıklık yaratır (özellikle daha önce C/C++ gibi başka dillerde programlamışlarsa). Bunun nedeni, diğer dillerin çoğunun karakterleri işlemek için 1 baytlık veri türlerini kullanmasıdır. Örneğin, C / C++'da char türü çoğu durumda hem karakter işleme hem de bayt işleme için kullanılır - ayrım yoktur. Java'nın kendi bayt türü vardır - bayt türü. Bu nedenle, C tabanlı bir karakter, bir Java baytına karşılık gelir ve C dünyasından bir Java karakteri, wchar_t türüne en yakındır. Karakter ve bayt kavramlarını açıkça ayırmak gerekir - aksi takdirde yanlış anlama ve problemler garanti edilir.

Java, neredeyse başlangıcından beri karakter kodlaması için Unicode standardını kullanıyor. Java kitaplığı işlevlerinin içinde görülmesi bekleniyor tür değişkenleri Unicode kodlarıyla temsil edilen karakter karakterleri. Prensip olarak, elbette, oraya her şeyi doldurabilirsiniz - sayılar sayılardır, işlemci her şeye dayanır, ancak herhangi bir işlem için kütüphane işlevleri, Unicode kodlamasının verildiği varsayımına göre hareket eder. Böylece, karakter kodlamasının sabit olduğunu güvenle varsayabilirsiniz. Ama bu JVM'nin içinde. Veriler dışarıdan okunduğunda veya dışarıya iletildiğinde, yalnızca bir türle temsil edilebilir - bayt türü. Diğer tüm türler, kullanılan veri biçimine bağlı olarak baytlardan oluşturulur. Kodlamaların devreye girdiği yer burasıdır - Java'da bu yalnızca karakter aktarımı için kullanılan bir veri biçimidir ve char türünde veri oluşturmak için kullanılır. Kütüphanede her kod sayfası için 2 dönüşüm sınıfı vardır (ByteToChar ve CharToByte). Bu sınıflar sun.io paketindedir. Karakterden bayta dönüştürürken karşılık gelen karakter bulunamazsa,? Karakteri ile değiştirilir.

Bu arada, JDK 1.1'in bazı eski sürümlerindeki bu kod sayfası dosyaları, dönüştürme hatalarına ve hatta çalışma zamanı istisnalarına neden olan hatalar içerir. Örneğin, bu KOI8_R kodlaması ile ilgilidir. Bunu yaparken yapılacak en iyi şey, sürümü daha sonraki bir sürümle değiştirmektir. Sun'ın açıklamasına göre, bu sorunların çoğu JDK 1.1.6'da çözülmüştür.

JDK 1.4'ten önce, kullanılabilir kodlamalar kümesi yalnızca JDK satıcısı tarafından belirlenirdi. 1.4 ile başlayarak, zaten kendi kodlamanızı oluşturabileceğiniz (örneğin, nadiren kullanılan, ancak sizin için çok gerekli olan) yeni bir API ortaya çıktı (java.nio.charset paketi).

dize sınıfı

Çoğu durumda Java, dizeleri temsil etmek için java.lang.String türünde bir nesne kullanır. Bu, bir karakter dizisini (char) dahili olarak depolayan ve karakterleri işlemek için birçok yararlı yöntem içeren normal bir sınıftır. En ilginç olanı, ilk parametre olarak bir bayt dizisine sahip yapıcılar ve getBytes () yöntemleridir. Bu yöntemlerle, bayt dizilerinden dizelere veya tam tersine dönüşümler gerçekleştirebilirsiniz. Bu durumda hangi kodlamanın kullanılacağını belirtmek için, bu yöntemlerin adını belirleyen bir dize parametresi vardır. Örneğin, baytları KOI-8'den Windows-1251'e şu şekilde dönüştürebilirsiniz:

// Veri kodlanmış KOI-8 bayt koi8Data = ...; // KOI-8'den Unicode'a dönüştür String string = new String (koi8Data, "KOI8_R"); // Unicode'dan Windows-1251'e Dönüştür bayt winData = string.getBytes ("Cp1251");

Modern JDK'larda bulunan ve Rusça harfleri destekleyen 8 bitlik kodlamaların listesi aşağıdaki bölümde bulunabilir.

Kodlama, karakterler için bir veri biçimi olduğundan, Java'daki bilindik 8 bitlik kodlamalara ek olarak, eşit düzeyde çok baytlı kodlamalar da vardır. Bunlara UTF-8, UTF-16, Unicode vb. dahildir. Örneğin, UnicodeLittleUnmarked biçiminde baytları bu şekilde alabilirsiniz (16-bit Unicode kodlama, önce düşük bayt, bayt sırası işareti yok):

// Unicode'dan Unicode'a Dönüştür bayt verisi = string.getBytes ("UnicodeLittleUnmarked");

Bu tür dönüşümlerde hata yapmak kolaydır - bayt verilerinin kodlaması, bayttan karaktere dönüştürürken belirtilen parametreyle eşleşmiyorsa, kayıt doğru şekilde gerçekleştirilmeyecektir. Bazen bundan sonra doğru karakterleri çıkarabilirsiniz, ancak çoğu zaman, verilerin bir kısmı geri dönüşü olmayan bir şekilde kaybolur.

Gerçek bir programda, kod sayfasını açıkça belirtmek her zaman uygun değildir (daha güvenilir olmasına rağmen). Bunun için varsayılan bir kodlama tanıtıldı. Varsayılan olarak, sisteme ve ayarlarına bağlıdır (Rus Windows için Cp1251 kodlaması benimsenmiştir) ve eski JDK'larda file.encoding sistem özelliği ayarlanarak değiştirilebilir. JDK 1.3'te bu ayarı değiştirmek bazen işe yarıyor, bazen çalışmıyor. Bu, aşağıdakilerden kaynaklanır: başlangıçta, file.encoding bilgisayarın bölgesel ayarlarına göre ayarlanır. Varsayılan kodlama referansı, ilk dönüştürme sırasında dahili olarak hatırlanır. Bu durumda, file.encoding kullanılır, ancak bu dönüştürme, JVM başlatma argümanlarını kullanmadan önce bile gerçekleşir (aslında, onları ayrıştırırken). Aslında Sun, bu özelliğin sistem kodlamasını yansıttığını ve komut satırında değiştirilmemesi gerektiğini söylüyor (örneğin, BugID hakkındaki yorumlara bakın) Ancak, JDK 1.4 Beta 2'de bu ayarın değiştirilmesi yeniden etkili olmaya başladı. Nedir bu, bilinçli bir değişiklik ya da tekrar kaybolabilecek bir yan etki - Güneş-koyun henüz net bir cevap vermedi.

Bu kodlama, sayfa adı açıkça belirtilmediğinde kullanılır. Bu her zaman hatırlanmalıdır - Java, oluşturmak için ilettiğiniz baytların kodlamasını tahmin etmeye çalışmayacaktır. dizeler Dize(bu konudaki düşüncelerinizi de okuyamaz :-). Yalnızca geçerli varsayılan kodlamayı kullanır. Çünkü bu ayar tüm dönüşümler için aynıdır, bazen sorun yaşayabilirsiniz.

Baytlardan karakterlere veya tam tersine dönüştürmek için şunu kullanın: bir tek bu yöntemlerle. Çoğu durumda, basit bir tür dönüştürme kullanılamaz - karakter kodlaması dikkate alınmayacaktır. Örneğin, en yaygın hatalardan biri, bir InputStream'den read () yöntemini kullanarak verileri bayt düzeyinde okumak ve ardından elde edilen değeri char türüne dönüştürmektir:

InputStream = ..; int b; StringBuffer sb = yeni StringBuffer(); while ((b = is.read ())! = - 1) (sb.append ((char) b); // <- так делать нельзя ) Dize s = sb.toString();

Yazı tipine dikkat edin - "(char) b". Bayt değerleri yeniden kodlama yerine basitçe char'a kopyalanır (değer aralığı 0-0xFF'dir, Kiril alfabesinin olduğu yer değil). Bu kopyalama, ISO-8859-1 kodlamasına (bire bir ilk 256 Unicode değerine karşılık gelir) karşılık gelir; bu, bu kodun basitçe onu kullandığını varsayabiliriz (içindeki karakterlerin olduğu kod yerine). orijinal veriler aslında kodlanmıştır). Alınan değeri görüntülemeye çalışırsanız, ekranda ya sorular ya da krakozy bir şekilde olacaktır. Örneğin, Windows kodlamasında "ABC" dizesini okurken, bunun gibi bir şey kolayca görüntülenebilir: "АÁВ". Bu tür kodlar genellikle Batı'daki programcılar tarafından yazılır - İngilizce harflerle çalışır ve tamam. Bu kodu düzeltmek kolaydır - StringBuffer'ı ByteArrayOutputStream ile değiştirmeniz yeterlidir:

InputStream = ..; int b; ByteArrayOutputStream baos = yeni ByteArrayOutputStream (); while ((b = is.read ())! = - 1) (baos.write (b);) // Varsayılan kodlamayı kullanarak baytları dizgeye dönüştürün String s = baos.toString(); // Belirli bir kodlamaya ihtiyacınız varsa, bunu toString () çağırırken belirtmeniz yeterlidir: // // s = baos.toString ("Cp1251");
Yaygın hatalar hakkında daha fazla ayrıntı için bölüme bakın.

Rus harflerinin 8 bitlik kodlamaları

İşte yaygınlaşan Rus harflerinin 8 bitlik ana kodlamaları:

Ana isme ek olarak, eş anlamlıları da kullanabilirsiniz. Bunların seti, JDK'nın farklı sürümlerinde farklılık gösterebilir. JDK 1.3.1'den bir liste:

  • Cp1251:
    • Windows-1251
  • Cp866:
    • IBM866
    • IBM-866
    • CP866
    • CSIBM866
  • KOI8_R:
    • KOI8-R
    • CSKOI8R
  • ISO8859_5:
    • ISO8859-5
    • ISO-8859-5
    • ISO_8859-5
    • ISO_8859-5: 1988
    • ISO-IR-144
    • 8859_5
    • Kiril
    • CSISOLatinKiril
    • IBM915
    • IBM-915
    • Cp915

Ayrıca, eşanlamlılar, ana ismin aksine, büyük/küçük harfe duyarlı değildir - bu, uygulamanın bir özelliğidir.

Bu kodlamaların bazı JVM'lerde bulunmayabileceğini belirtmekte fayda var. Örneğin, JRE'nin iki farklı sürümünü Sun'ın web sitesinden ABD ve Uluslararası olarak indirebilirsiniz. ABD sürümünde, yalnızca minimum - ISO-8859-1, ASCII, Cp1252, UTF8, UTF16 ve birkaç çift baytlı Unicode varyasyonu vardır. Diğer her şey yalnızca Uluslararası sürümde mevcuttur. Bazen bu nedenle, Rus harflerine ihtiyaç duymasa bile, programın başlatılmasıyla bir komisyonla karşılaşabilirsiniz. Bunu yaparken oluşan tipik bir hata:

VM Java / lang / ClassNotFoundException başlatılırken hata oluştu: sun / io / ByteToCharCp1251

Rus bölgesel ayarlarına dayanan JVM'nin varsayılan kodlamayı Cp1251'de ayarlamaya çalışması nedeniyle tahmin edilmesi zor olmadığı için ortaya çıkar. ABD versiyonunda böyle bir destek sınıfı yok, doğal olarak kopuyor.

Dosyalar ve veri akışları

Baytların karakterlerden kavramsal olarak ayrılması gibi, Java da bayt akışları ve karakter akışları arasında ayrım yapar. Baytlarla çalışma, InputStream veya OutputStream sınıflarını (artı benzersiz RandomAccessFile sınıfı) doğrudan veya dolaylı olarak devralan sınıflarla temsil edilir. Sembollerle çalışmak, tatlı bir çift Reader / Writer sınıfı (ve tabii ki onların torunları) tarafından temsil edilir.

Bayt akışları, dönüştürülmemiş baytları okumak/yazmak için kullanılır. Baytların yalnızca bazı kodlamalarda karakterler olduğunu biliyorsanız, bir karakter akışı almak ve onunla doğrudan çalışmak için InputStreamReader ve OutputStreamWriter özel dönüştürme sınıflarını kullanabilirsiniz. Bu genellikle düz metin dosyaları için veya İnternet'in birçok ağ protokolüyle çalışırken kullanışlıdır. Bu durumda, karakter kodlaması, converter sınıfının yapıcısında belirtilir. Örnek:

// Unicode string String string = "..."; // Dizeyi Cp866 kodlamasında bir metin dosyasına yazın PrintWriter pw = yeni PrintWriter // string yazma yöntemleri olan sınıf(yeni OutputStreamWriter // sınıf dönüştürücü(yeni FileOutputStream ("file.txt"), "Cp866"); pw.println (dize); // satırı dosyaya yaz pw.kapat();

Akış, farklı kodlamalarda veriler içeriyorsa veya karakterler diğer ikili verilerle karıştırılıyorsa, bayt dizilerini okumak ve yazmak ve dönüştürme için String sınıfının daha önce bahsedilen yöntemlerini kullanmak daha iyidir. Örnek:

// Unicode string String string = "..."; // Dizeyi iki kodlamada bir metin dosyasına yazın (Cp866 ve Cp1251) OutputStream işletim sistemi = new FileOutputStream ("file.txt"); // dosyaya bayt yazma sınıfı // Dizeyi Cp866 kodlamasında yaz os.write (string.getBytes ("Cp866")); // Dizeyi Cp1251 kodlamasında yaz os.write (string.getBytes ("Cp1251")); os.kapat ();

Java'daki konsol geleneksel olarak akışlarla temsil edilir, ancak ne yazık ki karakterler değil, baytlar. Gerçek şu ki, karakter akışları yalnızca JDK 1.1'de (tüm kodlama mekanizmasıyla birlikte) ortaya çıktı ve konsol G / Ç'ye erişim, JDK 1.0'da tasarlandı ve bu da PrintStream sınıfı şeklinde bir ucube görünümüne yol açtı. Bu sınıf, aslında konsolun çıktısına erişim sağlayan System.out ve System.err değişkenlerinde kullanılır. Tüm hesaplara göre, bu bir bayt akışıdır, ancak dizeleri yazmak için bir sürü yöntemi vardır. İçine bir dize yazdığınızda, Windows için genellikle kabul edilemez olan varsayılan kodlama kullanılarak dahili olarak baytlara dönüştürülür - varsayılan kodlama Cp1251 (Ansi) olacaktır ve konsol penceresi için genellikle kullanmanız gerekir. Cp866 (OEM). Bu hata 97. yılda () kaydedildi, ancak Sun-koyun bunu düzeltmek için acele etmiyor gibi görünüyor. PrintStream'de kodlamayı ayarlamak için bir yöntem olmadığından, bu sorunu çözmek için System.setOut() ve System.setErr() yöntemlerini kullanarak standart sınıfı kendi sınıfınızla değiştirebilirsiniz. Örneğin, programlarımdaki olağan başlangıç ​​şudur:

... public static void main (String argümanlar) ( // Konsol mesajlarının çıktısını istenen kodlamada ayarlayın try (String consoleEnc = System.getProperty ("console.encoding", "Cp866"); System.setOut (yeni CodepagePrintStream (System.out, consoleEnc)); System.setErr (yeni CodepagePrintStream (System.err, consoleEnc)); ) catch (UnsupportedEncodingException e) (System.out.println ("Konsol kod sayfası kurulamıyor:" + e);) ...

CodepagePrintStream sınıfının kaynaklarını şu sitede bulabilirsiniz: CodepagePrintStream.java.

Veri biçimini kendiniz oluşturuyorsanız, çok baytlı kodlamalardan birini kullanmanızı öneririm. En uygun biçim genellikle UTF8'dir - içindeki ilk 128 değer (ASCII) bir baytta kodlanır, bu da genellikle toplam veri miktarını önemli ölçüde azaltabilir (bu kodlamanın temel alındığı hiçbir şey için değildir). XML dünyası). Ancak UTF8'in bir dezavantajı vardır - gereken bayt sayısı karakter koduna bağlıdır. Bunun kritik olduğu durumlarda, iki baytlık Unicode biçimlerinden biri (UnicodeBig veya UnicodeLittle) kullanılabilir.

Veri tabanı

Veritabanından karakterleri doğru okumak için genellikle JDBC sürücüsüne veritabanında gerekli karakter kodlamasını söylemek yeterlidir. Tam olarak nasıl belirli sürücüye bağlıdır. Yakın geçmişin aksine, günümüzde birçok sürücü zaten bu ayarı desteklemektedir. İşte bildiğim bazı örnekler.

JDBC-ODBC köprüsü

Bu, en sık kullanılan sürücülerden biridir. JDK 1.2 ve daha eski sürümlerdeki köprü, istenen kodlamaya göre kolayca yapılandırılabilir. Bu, tabana bir bağlantı açmak için geçirilen parametre kümesine ek bir charSet özelliği eklenerek yapılır. Varsayılan dosya.encoding'dir. Bu böyle bir şey yapılır:

// bir bağlantı kurun

Linux için Oracle 8.0.5 JDBC-OCI sürücüsü

Veritabanından veri alırken, bu sürücü "kendi" kodlamasını NLS_LANG ortam değişkenini kullanarak belirler. Bu değişken bulunamazsa, kodlamanın ISO-8859-1 olduğunu varsayar. İşin püf noktası, NLS_LANG'nin bir Java sistem özelliği (file.encoding gibi) değil, bir ortam değişkeni (set komutuyla ayarlanmış) olması gerektiğidir. Sürücü, Apache + Jserv sunucu uygulaması motorunda kullanılıyorsa, ortam değişkeni jserv.properties dosyasında ayarlanabilir:

wrapper.env = NLS_LANG = American_America.CL8KOI8R
Bununla ilgili bilgiler, kendisine özel olarak teşekkür edilen Sergei Bezrukov tarafından gönderildi.

DBF ile çalışmak için JDBC sürücüsü (zyh.sql.dbf.DBFDriver)

Bu sürücü daha yeni Rus harfleriyle çalışmayı öğrendi. getPropertyInfo () tarafından charSet özelliğini anladığını bildirmesine rağmen, bu bir kurgudur (en azından 30.07.20001 tarihli sürümde). Gerçekte, CODEPAGEID özelliğini ayarlayarak kodlamayı özelleştirebilirsiniz. Rusça karakterler için iki değer mevcuttur - Cp866 için "66" ve Cp1251 için "C9". Örnek:

// Baz ile bağlantı parametreleriÖzellikler connInfo = yeni Özellikler (); connInfo.put ("CODEPAGEID", "66"); // Cp866 kodlaması // bir bağlantı kurun Bağlantı db = DriverManager.getConnection ("jdbc: DBF: / C: / MyDBFFiles", connInfo);
FoxPro biçiminde DBF dosyalarınız varsa, kendi özellikleri vardır. Gerçek şu ki FoxPro, DBF oluşturulurken kullanılan kod sayfasının (0x1D ofsetli bayt) kimliğini dosya başlığına kaydeder. Bir tablo açarken, sürücü "CODEPAGEID" parametresini değil, başlıktaki değeri kullanır (bu durumda parametre yalnızca yeni tablolar oluşturulurken kullanılır). Buna göre, her şeyin düzgün çalışması için DBF dosyasının doğru kodlama ile oluşturulması gerekir - aksi takdirde sorunlar olacaktır.

MySQL (org.gjt.mm.mysql.Driver)

Bu sürücü ile her şey oldukça basit:

// Baz ile bağlantı parametreleriÖzellikler connInfo = new Poperties (); connInfo.put ("kullanıcı", kullanıcı); connInfo.put ("şifre", geçiş); connInfo.put ("useUnicode", "true"); connInfo.put ("characterEncoding", "KOI8_R"); Bağlantı bağlantısı = DriverManager.getConnection (dbURL, aksesuarlar);

InterBase (interbase.interclient.Driver)

Bu sürücü için "charSet" parametresi çalışır:
// Baz ile bağlantı parametreleriÖzellikler connInfo = yeni Özellikler (); connInfo.put ("kullanıcı", kullanıcı adı); connInfo.put ("şifre", şifre); connInfo.put ("charSet", "Cp1251"); // bir bağlantı kurun Bağlantı db = DriverManager.getConnection (dataurl, connInfo);

Ancak veritabanı ve tabloları oluştururken karakter kodlamasını belirtmeyi unutmayınız. Rus dili için "UNICODE_FSS" veya "WIN1251" değerlerini kullanabilirsiniz. Örnek:

CREATE DATABASE "E: \ ProjectHolding \ DataBase \ HOLDING.GDB" PAGE_SIZE 4096 VARSAYILAN KARAKTER SET UNICODE_FSS; CREATE TABLE RUSSIAN_WORD ("NAME1" VARCHAR (40) KARAKTER AYARI UNICODE_FSS NULL DEĞİL, "NAME2" VARCHAR (40) KARAKTER AYARI WIN1251 NULL DEĞİL, BİRİNCİL ANAHTAR ("NAME1"));

InterClient'in 2.01 sürümünde bir hata var - Rus dili için mesajların bulunduğu kaynak sınıfları burada doğru bir şekilde derlenmiyor. Büyük olasılıkla, geliştiriciler derlerken kaynak kodlamayı belirtmeyi unutmuşlardır. Bu hatayı düzeltmenin iki yolu vardır:

  • interclient.jar yerine interclient-core.jar kullanın. Aynı zamanda, Rusça kaynaklar olmayacak ve İngilizce olanlar otomatik olarak alınacaktır.
  • Dosyaları normal Unicode'a yeniden derleyin. Sınıf dosyalarını ayrıştırmak nankör bir iştir, bu nedenle JAD kullanmak daha iyidir. Ne yazık ki JAD, ISO-8859-1 setinden karakterlerle karşılaşırsa, bunları 8 basamaklı kodlamada verir, bu nedenle standart native2ascii kodlayıcıyı kullanamazsınız - kendi kodunuzu yazmanız gerekir (Kod çözme programı). Bu sorunlarla uğraşmak istemiyorsanız, hazır dosya kaynaklarla (sürücülü yamalı kavanoz - interclient.jar, ayrı kaynak sınıfları - interclient-rus.jar).

Ancak JDBC sürücüsünü istenen kodlamaya ayarlamış olsanız bile bazı durumlarda sorun yaşayabilirsiniz. Örneğin, JDK 1.3.x'ten JDBC-ODBC köprüsünde harika yeni JDBC 2 kayan imleçleri kullanmaya çalışırken, Rusça harflerin orada çalışmadığını hemen görürsünüz (updateString () yöntemi).

Bu hatayla ilgili küçük bir hikaye var. Onu ilk keşfettiğimde (JDK 1.3 rc2 altında), BugParade () ile kaydettim. JDK 1.3.1'in ilk betası çıktığında bu hata düzeltildi olarak işaretlendi. Memnun kaldım, bu betayı indirdim, testi yaptım - çalışmıyor. Bu konuda Sun-sheep'e yazdım - yanıt olarak bana düzeltmenin gelecekteki sürümlere dahil edileceğini yazdılar. Tamam, bekleyelim diye düşündüm. Zaman geçti, 1.3.1 sürümü yayınlandı ve ardından beta 1.4 yayınlandı. Sonunda kontrol etmek için zaman ayırdım - yine çalışmıyor. Anne, anne, anne ... - yankı alışkanlıkla yankılandı. Sun'a öfkeli bir mektuptan sonra, Hindistan şubesine parçalamak için verdikleri yeni bir hatayı () tanıttılar. Kızılderililer kodla uğraştı ve her şeyin 1.4 beta3'te düzeltildiğini söyledi. Bu sürümü indirdim, altında bir test senaryosu çalıştırdım, işte sonuç -. Görünüşe göre, sitede dağıtılan beta3 (derleme 84), son düzeltmenin dahil edildiği beta3 (derleme 87) değil. Şimdi düzeltmenin 1.4 rc1'e dahil edileceğine söz veriyorlar ... Genel olarak, anlıyorsunuz :-)

Java programlarının kaynak kodundaki Rus harfleri

Belirtildiği gibi, program yürütülürken Unicode kullanır. Kaynak dosyalar sıradan editörlerde yazılır. Far kullanıyorum, muhtemelen favori editörünüz var. Bu düzenleyiciler, dosyaları 8 bit biçiminde kaydeder; bu, yukarıdakine benzer bir mantık yürütmenin bu dosyalar için de geçerli olduğu anlamına gelir. Farklı derleyici sürümleri, karakter dönüştürmeyi biraz farklı şekilde gerçekleştirir. JDK 1.1.x'in önceki sürümleri, standart olmayan -J seçeneğiyle geçersiz kılınabilen file.encoding ayarını kullanır. Daha yenilerinde (Denis Kokarev tarafından bildirildiği gibi - 1.1.4'ten başlayarak), kullanılan kodlamayı belirtebileceğiniz ek bir -kodlama parametresi eklendi. Derlenmiş sınıflarda, dizeler Unicode biçiminde (daha doğrusu UTF8 biçiminin değiştirilmiş bir sürümünde) temsil edilir, bu nedenle en ilginç şey derleme sırasında olur. Bu nedenle en önemli şey kaynak kodlarınızı hangi kodda kodladığını bulmak ve derlerken doğru değeri belirtmektir. Varsayılan olarak, aynı kötü şöhretli file.encoding kullanılacaktır. Derleyiciyi çağırmaya bir örnek:

Bu ayarı kullanmaya ek olarak, bir yöntem daha vardır - karakter kodunun belirtildiği "\ uXXXX" biçiminde harfleri belirtmek için. Bu yöntem tüm sürümlerde çalışır ve bu kodları almak için standart bir yardımcı program kullanabilirsiniz.

Herhangi bir IDE kullanırsanız, kendi aksaklıkları olabilir. Bu IDE'ler genellikle kaynakları okumak / kaydetmek için varsayılan kodlamayı kullanır - bu nedenle işletim sisteminizin bölgesel ayarlarına dikkat edin. Ek olarak, bariz hatalar olabilir - örneğin, oldukça iyi IDE ölçeği CodeGuide, büyük Rus harfi "T" yi iyi sindirmez. Yerleşik kod analizörü bu harfi çift tırnak olarak yorumlar, bu da doğru kodun hatalı olarak algılanmasına yol açar. Bununla savaşabilirsiniz ("T" harfini "\ u0422" koduyla değiştirerek), ancak tatsız. Görünüşe göre, ayrıştırıcının içinde bir yerde, karakterlerin baytlara açık bir dönüşümü (örneğin: bayt b = (bayt) c) kullanılıyor, bu nedenle 0x0422 ("T" harfinin kodu) yerine kod 0x22 ( çift ​​alıntı kodu).

JBuilder'ın başka bir sorunu daha var ama bu daha çok ergonomiyle ilgili. Gerçek şu ki, JBuilder'ın varsayılan olarak çalıştığı JDK 1.3.0'da, yeni oluşturulan GUI pencerelerinin etkinleştirildiğinde, işletim sisteminin bölgesel ayarlarına bağlı olarak klavye düzenini otomatik olarak içermesi nedeniyle bir hata () vardır. Onlar. Rus bölgesel ayarlarınız varsa, sürekli olarak program yazarken araya giren Rus düzenine geçmeye çalışacaktır. JBuilder.ru sitesinde, JVM'deki mevcut yerel ayarı Locale.US olarak değiştiren birkaç yama vardır, ancak en iyi yol, bu hatayı düzelten JDK 1.3.1'e yükseltmektir.

Acemi JBuilder kullanıcıları da böyle bir sorunla karşılaşabilir - Rusça harfler "\ uXXXX" kodları olarak kaydedilir. Bunu önlemek için, Varsayılan Proje Özellikleri iletişim kutusundaki Genel sekmesinde, Kodlama alanında Varsayılanı Cp1251 olarak değiştirin.

Derleme için standart javac dışında bir derleyici kullanıyorsanız, karakter dönüşümünü nasıl gerçekleştirdiğine dikkat edin. Örneğin, IBM jikes derleyicisinin bazı sürümleri, ISO-8859-1 :-) dışında kodlamalar olduğunu anlamaz. Bunun için yamalı sürümler vardır, ancak genellikle orada bazı kodlamalar da dikilir - javac'ta olduğu gibi bir kolaylık yoktur.

JavaDoc

Kaynak için HTML belgeleri oluşturmak için standart JDK dağıtımında bulunan javadoc yardımcı programı kullanılır. Kodlamaları belirtmek için en fazla 3 parametresi vardır:

  • -kodlama - bu ayar kaynak kodlamasını belirtir. Varsayılan dosya.encoding'dir.
  • -docencoding - bu ayar, oluşturulan HTML dosyalarının kodlamasını belirtir. Varsayılan dosya.encoding'dir.
  • -charset - bu ayar, oluşturulan HTML dosyalarının başlıklarına yazılacak kodlamayı belirtir ( ). Açıkçası, önceki ayar ile aynı olmalıdır. Bu ayar atlanırsa meta etiket eklenmez.

Özellikler dosyalarındaki Rus harfleri

Kaynak yükleme yöntemleri, belirli bir şekilde çalışan özellik dosyalarını okumak için kullanılır. Aslında, okuma için, file.encoding (ISO-8859-1 kodlaması kaynaklarda sabit kodlanmıştır) kullanmayan Properties.load yöntemi kullanılır, bu nedenle Rusça harfleri belirtmenin tek yolu "\ uXXXX" kullanmaktır. biçim ve yardımcı program.

Properties.save yöntemi, JDK 1.1 ve 1.2'de farklı şekilde çalışır. 1.1 sürümlerinde, yalnızca yüksek baytı attı, bu nedenle yalnızca İngilizce harflerle doğru çalıştı. 1.2, yükleme yöntemine yansıtılmış olarak çalışması için "\ uXXXX"e ters dönüştürme yapar.

Özellik dosyalarınız kaynak olarak değil, sıradan yapılandırma dosyaları olarak yükleniyorsa ve bu davranıştan memnun değilseniz, tek bir çıkış yolu vardır, kendi yükleyicinizi yazın.

Servlet'lerde Rusça harfler.

Peki, aynı Servlet'lerin ne işe yaradığını, sanırım biliyorsunuz. Değilse, önce belgeleri okumak en iyisidir. Burada sadece Rus harfleriyle çalışmanın özellikleri açıklanmaktadır.

Peki özellikleri nelerdir? Servlet bir istemciye bir yanıt gönderdiğinde, bu yanıtı göndermenin iki yolu vardır - bir OutputStream (getOutputStream() yöntemi) veya bir PrintWriter (getWriter() yöntemi). İlk durumda, bayt dizileri yazıyorsunuz, bu nedenle yukarıdaki akışlara yazma yöntemleri uygulanabilir. PrintWriter durumunda, set kodlamasını kullanır. Her durumda, sunucu tarafında doğru karakter dönüşümü için setContentType() yöntemi çağrılırken kullanılan kodlamayı doğru bir şekilde belirtmelisiniz. Bu yönerge getWriter() çağrılmadan veya OutputStream'e ilk yazılmadan önce yapılmalıdır. Örnek:

// Yanıtın kodlamasını ayarla // Bazı motorların izin vermediğini unutmayın // arasındaki boşluk ";" ve "karakter seti" tepki.setContentType ("metin / html; karakter kümesi = UTF-8"); PrintWriter çıkışı = yanıt.getWriter(); // Kontrol edilecek kodlamanın adının çıktısında hata ayıklayın out.println ("Kodlama:" + answer.getCharacterEncoding ()); ... dışarı.kapat (); )

Müşteriye cevaplar vermekle ilgili. Ne yazık ki, giriş parametreleriyle o kadar kolay değil. Giriş parametreleri, "application / x-www-form-urlencoded" MIME tipine göre tarayıcı baytı tarafından kodlanır. Alexey Mendelev'in dediği gibi, tarayıcılar şu anda ayarlanmış kodlamayı kullanarak Rusça harfleri kodlar. Ve elbette, onun hakkında hiçbir şey rapor edilmedi. Buna göre, örneğin, 2.0'dan 2.2'ye kadar olan JSDK sürümlerinde bu hiçbir şekilde kontrol edilmez ve dönüştürme için ne tür bir kodlamanın kullanılacağı kullanılan motora bağlıdır. 2.3 spesifikasyonundan başlayarak, setCharacterEncoding () yöntemi olan javax.servlet.ServletRequest için kodlamayı ayarlamak mümkün hale geldi. Resin ve Tomcat'in en son sürümleri bu özelliği zaten desteklemektedir.

Dolayısıyla şanslıysanız ve Servlet 2.3 destekli bir sunucunuz varsa, o zaman her şey oldukça basit:

public void doPost (HttpServletRequest isteği, HttpServletResponse yanıtı) ServletException, IOException ( // Mesaj kodlaması request.setCharacterEncoding ("Cp1251"); Dize değeri = request.getParameter ("değer"); ...

request.setCharacterEncoding () yöntemini uygulamada önemli bir incelik vardır - uygulanması gerekir önce veri isteğine yapılan ilk çağrı (örneğin, request.getParameter ()). İsteği sunucu uygulamasına gelmeden önce işleyen filtreler kullanırsanız, filtrelerden birinde istekten bazı parametrelerin (örneğin yetkilendirme için) ve sunucu uygulamasında request.setCharacterEncoding () okunabilmesi için sıfır olmayan bir şans vardır. çalışmayacak...

Bu nedenle istek kodlamasını ayarlayan bir filtre yazmak ideolojik olarak daha doğrudur. Ayrıca web.xml'deki filtreler zincirinde ilk olması gerekir.

Böyle bir filtreye bir örnek:

java.io'yu içe aktar *; java.util'i içe aktar *; javax.servlet'i içe aktar *; javax.servlet.http'yi içe aktar *; public class CharsetFilter Filter uygular (// private String kodlamasını kodlar; public void init (FilterConfig config) ServletException'ı ( // config'den oku kodlama = config.getInitParameter ("requestEncoding"); // kurulu değilse, Cp1251'i kurun if (kodlama == boş) kodlama = "Cp1251"; ) public void doFilter (ServletRequest isteği, ServletResponse yanıtı, sonraki FilterChain) IOException, ServletException (request.setCharacterEncoding (kodlama); next.doFilter (istek, yanıt);) public void destroy () () atar

Ve web.xml'deki yapılandırması:

Karakter Seti Filtresi Karakter Filtresi Karakter Seti Filtresi /*

Şanssızsanız ve daha fazlasına sahipseniz eski versiyon- sonuca ulaşmak için saptırmanız gerekir:

    Kodlamalarla çalışmanın orijinal yolu, Rus Apache tarafından sunulmaktadır - tam olarak nasıl olduğu açıklanmıştır.

  • FOP

    Program hiçbir yerde çalışmıyorsa, sorun yalnızca onda ve sizin elinizdedir. Yukarıda yazılanları dikkatlice tekrar okuyun ve bakın. Sorun yalnızca belirli bir ortamda kendini gösteriyorsa, sorun ayarlarda olabilir. Tam olarak nerede, hangi grafik kitaplığını kullandığınıza bağlıdır. AWT ise - font.properties.ru dosyasının doğru yapılandırılması yardımcı olabilir. Java 2'den doğru bir dosya örneği alınabilir. Bu sürüme sahip değilseniz, bu siteden indirebilirsiniz: Windows sürümü, Linux sürümü (ayrıca aşağıya bakın). Bu dosya, kullanılacak yazı tiplerini ve kod sayfalarını belirtir. İşletim sisteminin Rusça sürümü yüklüyse, bu dosyayı font.properties dosyasının bulunduğu yere eklemeniz yeterlidir. Bu İngilizce sürümse, bu dosyayı font.properties yerine yeniden yazmanız veya ek olarak mevcut bölgesel ayarları Rusça olarak değiştirmeniz gerekir. Bazen -Duser.language = ru ayarı işe yarayabilir, ancak çoğu zaman çalışmaz. file.encoding ile hemen hemen aynı sorunlar var - çalışıp çalışmaması JDK'ya bağlıdır (numaraya göre hataya bakın).

    Swing kitaplığı ile her şey daha basittir - her şey Java2D alt sistemi aracılığıyla çizilir. Standart iletişim kutularındaki (JOptionPane, JFileChooser, JColorChooser) etiketleri Rusça'ya dönüştürmek çok kolaydır - sadece birkaç kaynak dosyası oluşturmanız yeterlidir. Bunu zaten yaptım, böylece bitmiş dosyayı alıp lib \ ext veya CLASSPATH'e ekleyebilirsiniz. Karşılaştığım tek sorun, 1.2 rc1 ve 1.3 beta'dan başlayan JDK sürümlerinde, Java2D'deki bir hata nedeniyle standart yazı tiplerini (Arial, Courier New, Times New Roman vb.) kullanırken Win9x altında Rusça harflerin görüntülenmemesi. Hata oldukça tuhaf - standart yazı tiplerinde harf görüntüleri Unicode kodlarına göre değil, Cp1251 tablosuna (Ansi kodlaması) göre görüntülenir. Bu hata, BugParade'de numaranın altında kayıtlıdır. Varsayılan olarak Swing, font.properties.ru dosyasında belirtilen yazı tiplerini kullanır, bu nedenle bunları başkalarıyla değiştirmek yeterlidir ve Rusça harfler görünecektir. Ne yazık ki, çalışan yazı tipleri grubu küçüktür - bunlar Tahoma, Tahoma Bold yazı tipleri ve JDK dağıtımından iki yazı tipi grubudur - Lucida Sans * ve Lucida Typewriter * (font.properties.ru dosyası örneği). Bu yazı tiplerinin standart olanlardan nasıl farklı olduğu benim için net değil.

    1.3rc1 sürümünden beri bu sorun zaten çözülmüştür, bu yüzden JDK'yı güncellemeniz yeterlidir. JDK 1.2 zaten çok eski, bu yüzden kullanmanızı önermiyorum. Win95'in orijinal sürümünün Unicode'u desteklemeyen yazı tipleriyle birlikte geldiğine de dikkat edilmelidir - bu durumda yazı tiplerini Win98 veya WinNT'den kopyalayabilirsiniz.

    Tipik hatalar veya "W harfi nereye gitti?"

    Mektup Ş.

    Bu soru ("W harfi nereye gitti?") Genellikle acemi Java programcıları tarafından sorulur. Bakalım en sık nereye gidiyor. :-)

    İşte tipik bir HelloWorld tarzı program:

    public class Testi (public static void main (String args) (System.out.println ("ИЦУКЕНГШЩЗХЪ"));)
    Uzakta kaydet verilen kod Test.java dosyasına, derleyin ...
    C: \> javac Test.java
    ve koş ...
    C: \> Java Testi YTsUKENG? ЩЗХЪ

    Ne oldu? W harfi nereye gitti? Buradaki hile, iki hatanın karşılıklı olarak telafi edilmesidir. Far'ın metin düzenleyicisi, varsayılan olarak bir DOS kodlu dosya (Cp866) oluşturur. Javac derleyicisi, kaynağı okumak için file.encoding'i kullanır ( -encoding anahtarıyla aksi belirtilmedikçe). Ve Windows ortamı Rusça yerel ayarlarla varsayılan kodlama Cp1251'dir. Bu ilk hata. Sonuç olarak, derlenmiş Test.class dosyasındaki simgeler yanlış kodlara sahiptir. İkinci hata, çıktı için standart PrintStream'in kullanılmasıdır, bu da file.encoding'deki ayarı kullanır, ancak Windows'taki konsol penceresi, DOS kodlamasını kullanan karakterleri görüntüler. Cp1251 kodlaması karşılıklı olarak geçerli olsaydı, veri kaybı olmazdı. Ancak Cp866'daki W karakteri, Cp1251'de tanımlanmayan bir kod 152'ye sahiptir ve bu nedenle Unicode 0xFFFD karakteriyle eşlenir. Karakterden bayta geri dönüştürürken, bunun yerine "?" Karakteri kullanılır.

    Java.io.FileReader kullanarak bir metin dosyasındaki karakterleri okursanız ve sonra bunları System.out.println () kullanarak ekranda görüntülerseniz benzer bir telafiyle karşılaşabilirsiniz. Dosya Cp866 kodlamasında yazılmışsa, çıktı yine Ш harfi dışında doğru gidecektir.

    Doğrudan bayt dönüştürme<->karakter.

    Bu hata, yabancı Java programcılarının favorisidir. Açıklamanın başında biraz ayrıntılı olarak tartışılmıştır. Başkalarının kaynaklarına bakarsanız, her zaman açık tür dönüşümüne - (byte) veya (char) dikkat edin. Tırmıklar genellikle bu tür yerlere gömülür.

    Rus harfleriyle ilgili sorunları bulmak için algoritma

    Programınızda Rusça harflerin kaybolmasının nerede olabileceği hakkında hiçbir fikriniz yoksa, bir sonraki testi deneyebilirsiniz. Herhangi bir program bir girdi veri işlemcisi olarak kabul edilebilir. Rus harfleri aynı verilerdir, geçerler Genel dava işlemenin üç aşaması: bunlar bir yerden program belleğine (giriş) okunur, program içinde işlenir ve kullanıcıya gösterilir (çıkış). Sorunların yerini belirlemek için veriler yerine şu test satırını kaynak koduna dikmeyi ve "ABC \ u0410 \ u0411 \ u0412" ile çıktısını almayı denemelisiniz. Bundan sonra, ne elde ettiğinize bakın:

    • "ABVABV" görüyorsanız, kaynakların derlenmesi ve çıktı sizin için doğru çalışıyor.
    • "??? ABC" (veya ilk karakterin yerine "ABC" dışında herhangi bir karakter) görürseniz üç harf), sonra çıktı düzgün çalışıyor, ancak kaynakların derlenmesi doğru olmuyor - büyük olasılıkla -kodlama anahtarı belirtilmemiş.
    • Eğer görürsen "??????" (veya ikinci üç harfin yerine "ABC" dışındaki herhangi bir sembol), çıktı sizin için doğru çalışmıyor.

    Çıktıyı ve derlemeyi yapılandırdıktan sonra, girişi kolayca anlayabilirsiniz. Tüm zinciri kurduktan sonra, sorunlar gitmiş olmalıdır.

    native2ascii yardımcı programı hakkında

    Bu yardımcı program Sun JDK'nın bir parçasıdır ve kaynak kodunu ASCII biçimine dönüştürmek için tasarlanmıştır. O okur giriş dosyası, belirtilen kodlamayı kullanarak ve çıktıya "\ uXXXX" biçimindeki karakterleri yazar. -reverse anahtarını belirtirseniz, ters dönüştürme gerçekleştirilir. Bu program, kaynak dosyalarını (.properties) dönüştürmek veya Rus olmayan bölgesel ayarlara sahip bilgisayarlarda derlenebileceklerini düşünüyorsanız kaynakları işlemek için çok kullanışlıdır.

    Programı parametresiz çalıştırırsanız, diğer yardımcı programlar gibi bir tuş ipucu görüntülemek yerine standart girdi (stdin) ile çalışır. Bu, birçoğunun parametreleri belirtmenin gerekli olduğunu bile anlamamasına neden olur (belki de belgelere bakma gücünü ve cesaretini bulanlar hariç :-). Bu arada, bu yardımcı programın doğru çalışması için en azından kullanılan kodlamayı (-encoding anahtarı) belirtmelisiniz. Bu yapılmazsa, beklenenden biraz farklı olabilecek varsayılan kodlama (file.encoding) kullanılacaktır. Sonuç olarak, yanlış harf kodları aldığınızda (yanlış kodlama nedeniyle), kesinlikle doğru bir kodda hata aramak için çok zaman harcayabilirsiniz.

    Karakter dönüştürme yöntemi hakkında

    Birçok insan bu yöntemi yanlış kullanır, muhtemelen özünü ve sınırlarını tam olarak anlamaz. Yanlış yorumlanmışlarsa doğru harf kodlarını geri yüklemek için tasarlanmıştır. Yöntemin özü basittir: alınan yanlış karakterlerden uygun kod sayfası kullanılarak orijinal bayt dizisi geri yüklenir. Daha sonra, bu bayt dizisinden, zaten doğru olan sayfa kullanılarak normal karakter kodları elde edilir. Örnek:

    String res = new String (src.getBytes ("ISO-8859-1"), "Cp1251");

    Bu tekniği kullanırken çeşitli sorunlar olabilir. Örneğin, kurtarma için yanlış sayfa kullanılıyor veya bazı durumlarda değişebilir. Başka bir sorun, bazı sayfaların belirsiz bir bayt dönüşümü gerçekleştirmesi olabilir.<->karakter. Örneğin, numaraya göre hata açıklamasına bakın.

    Bu nedenle, bu yöntemi yalnızca en aşırı durumda, başka hiçbir şey yardımcı olmadığında kullanmaya değer ve karakterlerin yanlış dönüşümünün nerede gerçekleştiği konusunda net bir fikriniz var.

    Rus harfleri ve MS JVM

    Hangi nedenlerle olduğu belli değil, ancak Rus harflerini kodlamak için tüm dosyalardan yoksun, acrome Cp1251 (muhtemelen dağılımın boyutunu bu şekilde azaltmaya çalıştılar). Başka kodlamalara ihtiyacınız varsa, örneğin Cp866, o zaman ilgili sınıfları CLASSPATH'e eklemeniz gerekir. Ayrıca, Sun JDK'nın en son sürümlerinden gelen sınıflar uymuyor - Sun yapılarını uzun süredir değiştirdiğinden, sınıfların en son sürümleri Microsoft ile eşleşmiyor (MS, JDK 1.1.4'ten gelen yapıya sahip). Microsoft sunucusunda, prensip olarak, eksiksiz bir ek kodlama seti vardır, ancak yaklaşık 3 metre boyutunda bir dosya vardır ve sunucuları, indirmeye devam etmeyi desteklemiyor :-). Bu dosyayı indirmeyi başardım, jar ile yeniden paketledim, buradan alabilirsiniz.

    MS JVM altında çalışması gereken bir uygulama yazıyorsanız ve bir yerden (örneğin, sunucudaki bir dosyadan) baytları Cp1251 (örneğin, Cp866'da) dışında Rusça kodlamada okumanız gerekiyorsa, artık standart kodlama mekanizmasını kullanabilmek - uygulamaların sistem paketlerine sınıf eklemesi yasaktır. bu durumda sun.io paketidir. İki çıkış yolu vardır - ya sunucudaki dosyayı Cp1251'e (veya UTF-8'e) yeniden kodlamak ya da baytları Unicode'a dönüştürmeden önce, istenen kodlamadan baytları Cp1251'e dönüştürmek.

    Linux için Java'nın Ruslaştırılması

    Hemen söyleyeceğim - Linux ile çalışmıyorum ve burada verilen bilgiler okuyuculardan alınmıştır. bu açıklamanın... Bir yanlışlık bulursanız veya eklemek isterseniz - bana yazın.

    JVM'yi Linux'ta cyrilize ederken iki paralel sorun vardır:

    1. GUI bileşenlerinde Kiril çıktı sorunu
    2. Klavyeden Kiril alfabesini girme sorunu (X11'de)

    Para çekme sorunu bu şekilde çözülebilir ( bu algoritma Artemy E. Kapitula tarafından gönderildi):

    1. Normal Windows NT / 200 ttf yazı tiplerini X11'e yükleyin. Arial, Times New Roman, Courier New, Verdana ve Tahoma'yı öneririm - ve bunları bir yazı tipi sunucusu aracılığıyla değil, dosyaların bulunduğu bir dizin olarak bağlamak daha iyidir.
    2. Aşağıdaki font.properties.ru dosyasını $ Java_HOME / jre / lib dizinine ekleyin

    Giriş problemi yaklaşık olarak şu şekilde çözülür (bu algoritma Mikhail Ivanov tarafından gönderilmiştir):

    Aşağıdaki yapılandırmada Rus harflerinin girişini ayarlama:

    • Mandrake Linux 7.1
    • XFree86 3.3.6
    • IBM Java 1.3.0 (sürüm)

    Sorun:

    IBM Java 1.3, etiketlerde ve menülerde görünmelerine rağmen Rusça harflerin (timsah olarak görünen) girilmesine izin vermez.

    AWT'de XIM (-> xkb) kullanarak. (Bu kendi içinde kötü değil, sadece bu tür şeylerle dikkatli bir şekilde ele alınması gerekiyor + bazı xkb araçları bundan hoşlanmaz).

    xkb'yi yapılandırın (ve yerel ayarı (yerel ayar olmadan xkb ÇALIŞMAZ))

    Prosedür:

    1. yerel ayar açık ( / etc / profile veya ~ / .bash_profile gibi bir yerde)
      dışa aktar LANG = ru_RU.KOI8-R dışa aktar LC_ALL = ru_RU.KOI8-R
    2. edit (henüz yapılmadıysa) / etc / X11 / XF86Config. Klavye bölümü aşağıdakine benzer bir şey içermelidir:
      XkbKeycodes "xfree86" XkbTypes "default" XkbCompat "default" XkbSymbols "ru" XkbGeometry "pc" XkbRules "xfree86" XkbModel "pc101" XkbLayout "ru" XkbOptions "grp: shift_toggle "shift_toggle caps"
      not: bu xkb ayarı xrus (ve kikbd gibi diğerleri) ile uyumlu değildir ve bu nedenle onlara elveda demek zorunda kalacaksınız.
    3. X'ler yeniden başlatılır. Her şeyin çalıştığını kontrol etmeniz gerekiyor (terminaldeki ve uygulamalardaki Rus harfleri gibi)
    4. font.properties.ru -> $ Java_HOME / jre / lib
    5. fonts.dir -> $ Java_HOME / jre / lib / fontlar
    6. cd $ Java_HOME / jre / lib / yazı tipleri; rm fonts.scale; ln -s fonts.dir fonts.scale

    Artık Rusça harfler sorunsuz bir şekilde girilmeli ve gösterilmelidir.

Açıklamada bir yanlışlık görürseniz veya eklemek isterseniz bana yazın, adınız da bu listede görünecektir. :-)