Konsolda Java Rusça karakterleri. Özellikler dosyalarındaki Rus harfleri. Servlet'lerde Rusça harfler

  • 17.04.2019

kodlamalar

C'de programlamaya ilk başladığımda, ilk programım (HelloWorld'ü saymıyorum), metin dosyalarını ana GOST kodlamasından (bunu hatırlıyor musunuz? :-) alternatif bir programa dönüştürmek için bir programdı. 1991 yılındaydı. O zamandan beri çok şey değişti, ancak son 10 yılda bu tür programlar ne yazık ki 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 var çeşitli kodlamalar 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 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ı tercihen daha küçüktür - daha az ikili basamak dahil edilecek, hafızayı daha verimli kullanmak mümkün olacaktır. Bir dizi karakter ve sayı arasındaki bu yazışma aslında bir 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. (olmadığı kodlamalar neredeyse kullanım dışıdır). İngilizce harfler ve noktalama işaretleri bu aralıktadır, bu da bilgisayar sistemlerinde şaşırtıcı canlılıklarını belirler :-). Diğer diller o kadar mutlu bir konumda değil - hepsi kalan 128 numarada toplanmak zorunda.

tek kod

80'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 sembol için. Burada 256 karakterde tüm arzunuzu karşılamayacağınız açıktır. Oldukça uzun bir süre 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 94140 karakter tanımlıyor. Bu kadar çok sayıda karakter için muhtemelen 4 bayt (4294967296 karakter) kullanmanız gerekir. Bir süreliğine yeterli olabilir... :-)

Unicode karakter seti, her türlü tire ve fırfır, Yunanca, matematiksel, hiyeroglif, psödografik semboller vb. ile her türlü harfi içerir. Çok sevdiğimiz Kiril karakterleri de dahil (değer aralığı 0x0400-0x04ff). Yani bu yönden bir ayrımcılık yok.

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

Farklı bir işletim sisteminiz varsa veya resmi yorumla ilgileniyorsanız, tam karakter düzeni (tablolar) resmi Unicode web sitesinde (http://www.unicode.org/charts/web.html) bulunabilir.

karakter ve bayt türleri

Java'da semboller tahsis edilir ayrı tip char verileri 2 bayt uzunluğundadır. Bu genellikle yeni başlayanların kafasında karışıklık yaratır (özellikle daha önce C/C++ gibi başka dillerde programlamışlarsa). Gerçek şu ki, diğer dillerin çoğunda karakter işleme için 1 baytlık veri türleri kullanılı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 - burada ayırma yoktur. Java'nın bayt türü olan kendi bayt türü vardır. Bu nedenle, bir C-ish karakter, Java tabanlı bir bayta karşılık gelir ve C dünyasından Java tabanlı bir karakter, wchar_t öğesine en yakındır. Karakter ve bayt kavramlarını net bir şekilde 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 herhangi bir şey doldurabilirsiniz - sayılar sayılardır, işlemci her şeye dayanır, ancak herhangi bir işleme ile kütüphane işlevleri, Unicode kodlamasının verildiği varsayımına göre hareket eder. Böylece, char türünün sabit bir kodlamaya sahip olduğunu güvenle varsayabilirsiniz. Ama bu JVM'nin içinde. Veriler dışarıdan okunduğunda veya dışarıdan aktarıldığında, yalnızca bir türle, bayt türüyle temsil edilebilir. 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 karakterleri aktarmak için kullanılan bir veri biçimidir ve char türünde veri oluşturmak için kullanılır. Her kod sayfası için kitaplığın 2 dönüştürme 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, bunun yerine ? karakteri gelir.

Bu arada, bu kod sayfası dosyaları bazılarında erken sürümler JDK 1.1 hatalar içerir, hatalara neden olmak yürütme sırasında genel olarak kayıtlar, hatta istisnalar. Örneğin, bu KOI8_R kodlamasıyla ilgilidir. Yapılacak en iyi şey, sürümü daha sonra 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'ten bu yana, zaten kendi kodlamanızı oluşturabileceğiniz yeni bir API (paket java.nio.charset) ortaya çıktı (örneğin, nadiren kullanılan, ancak sizin için çok gerekli olan).

dize sınıfı

Çoğu durumda Java, dizeleri temsil etmek için java.lang.String türünde bir nesne kullanır. Bu, dahili olarak bir dizi karakter (char) depolayan ve karakterleri işlemek için birçok yararlı yöntem içeren normal bir sınıftır. En ilginç olanı, ilk parametresi olarak bir bayt dizisine sahip olan yapıcılar ve getBytes() yöntemleridir. Bu yöntemlerle, bir dizi bayttan dizelere veya tam tersine dönüşümler gerçekleştirebilirsiniz. Hangi kodlamanın kullanılacağını belirtmek için bu yöntemler, adını belirten bir dize parametresine sahiptir. Örneğin, baytları KOI-8'den Windows-1251'e nasıl dönüştürebileceğiniz aşağıda açıklanmıştır:

// KOI-8 kodlamasındaki veriler 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'da bulunan ve Rusça harfleri destekleyen 8 bitlik kodlamaların listesini aşağıdaki .

Kodlama, karakterler için bir veri biçimi olduğundan, bilinen 8 bitlik kodlamalara ek olarak, Java'nın 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ı göstergesi yok):

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

Bu tür dönüşümlerde hata yapmak kolaydır - bayt verilerinin kodlaması, bayttan char'a dönüştürürken belirtilen parametreyle eşleşmiyorsa, dönüştürme 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.

AT gerçek program kod sayfasını açıkça belirtmek her zaman uygun değildir (daha güvenilir olmasına rağmen). Bunun için varsayılan kodlama tanıtıldı. Varsayılan olarak, sisteme ve ayarlarına bağlıdır (Rusça Windows için Cp1251 kodlaması kabul edilir) ve daha 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 kodlamaya yapılan başvuru, ilk dönüştürme sırasında dahili olarak saklanır. Bu, file.encoding'i kullanır, ancak bu dönüştürme, JVM başlatma bağımsız değişkenleri kullanılmadan önce bile gerçekleşir (aslında, bunlar ayrıştırıldıklarında). Aslında Sun'a göre bu özellik sistem kodlamasını yansıtır ve komut satırında değiştirilmemelidir (bkz. örneğin BugID ile ilgili yorumlar) Ancak JDK 1.4 Beta 2'de bu ayarın değiştirilmesi yeniden etkili olmaya başladı. Nedir, bilinçli bir değişiklik ya da tekrar kaybolabilecek bir yan etki - Güneş koyunları 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. Sicim(ayrıca bu konudaki düşüncelerinizi okuyamaz :-). Yalnızca geçerli varsayılan kodlamayı kullanır. Çünkü bu ayar tüm dönüşümler için bir ayardır, bazen bir sorunla karşılaşabilirsiniz.

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

InputStream = ..; intb; 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 kodlamak yerine basitçe char'a kopyalanır (değer aralığı 0-0xFF'dir, Kiril alfabesinin bulunduğu yer değil). Böyle bir kopya, ISO-8859-1 kodlamasına karşılık gelir (bu, ilk 256 Unicode değerine bire bir karşılık gelir), bu, bu kodun basitçe onu kullandığını varsayabileceğimiz anlamına gelir (orijinaldeki karakterlerin olduğu kod yerine). veriler aslında kodlanmıştır). Alınan değeri görüntülemeye çalışırsanız, ekranda sorular veya anlamsız sözler olacaktır. Örneğin, Windows kodlamasında "ABC" dizesini okurken, bunun gibi bir şey kolayca görüntülenebilir: "ÀÁÂ". Batı'daki programcılar genellikle bu tür kodlar yazarlar - İngilizce harflerle çalışır ve sorun değil. Böyle bir kodu düzeltmek kolaydır - sadece StringBuffer'ı ByteArrayOutputStream ile değiştirin:

InputStream = ..; intb; ByteArrayOutputStream baos = yeni ByteArrayOutputStream(); while((b=is.read())!=-1) ( baos.write(b); ) // Varsayılan kodlamayı kullanarak baytları dizgeye dönüştürün Dizeler = baos.toString(); // Belirli bir kodlamaya ihtiyacınız varsa, bunu toString()'i çağırırken belirtmeniz yeterlidir: // // s = baos.toString("Cp1251");
Yaygın hatalar hakkında daha fazla bilgi 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. Setleri farklı JDK sürümlerinde farklılık gösterebilir. İşte JDK 1.3.1'deki 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ü Sun sitesinden indirilebilir - ABD ve Uluslararası. ABD sürümü yalnızca minimum minimuma sahiptir - ISO-8859-1, ASCII, Cp1252, UTF8, UTF16 ve birkaç çift baytlık Unicode varyasyonu. Diğer her şey yalnızca Uluslararası sürümdedir. Bazen, bu nedenle, Rus harflerine ihtiyaç duymasa bile, programın başlatılmasıyla bir komisyonla karşılaşabilirsiniz. Bununla oluşan tipik bir hata:

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

Tahmin edilmesi zor olmadığı için, Rus bölgesel ayarlarına dayanan JVM'nin varsayılan kodlamayı Cp1251'e ayarlamaya çalışması nedeniyle ortaya çıkıyor, ancak, çünkü 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ı olması gibi, Java da bayt akışları ve karakter akışları arasında ayrım yapar. Baytlarla çalışmak, InputStream veya OutputStream sınıflarını (artı benzersiz RandomAccessFile sınıfı) doğrudan veya dolaylı olarak devralan sınıflarla temsil edilir. Karakterlerle çalışmak, tatlı bir çift Reader / Writer sınıfı (ve tabii ki onların ardılları) 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 doğrudan onunla çalışmak için InputStreamReader ve OutputStreamWriter özel dönüştürücü 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. 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 pw = yeni Baskı Yazarı // string yazma yöntemleri olan sınıf(yeni OutputStreamWriter // dönüştürücü sınıfı(new FileOutputStream("file.txt"), "Cp866"); pw println(dize); // dosyaya dize yaz pw.close();

Akış, farklı kodlamalarda veri içeriyorsa veya karakterler diğer ikili verilerle karıştırılmışsa, o zaman bayt dizilerini (bayt) okuyup yazmak ve kayıt 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"); // bir 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 giriş / çıkışına erişim, JDK 1.0'da tasarlandı ve bu da PrintStream sınıfı biçiminde bir ucube görünümüne yol açtı. Bu sınıf, aslında konsol çıktısına erişim sağlayan System.out ve System.err değişkenlerinde kullanılır. Tüm göstergelere göre, bu bir bayt akışıdır, ancak dizeleri yazmak için bir sürü yöntemi vardır. Buna bir dize yazdığınızda, Windows için genellikle kabul edilemez olan varsayılan kodlama kullanılarak içeride baytlara dönüştürülür - varsayılan kodlama Cp1251 (Ansi) olacaktır ve konsol penceresi için genellikle Cp866 kullanmanız gerekir. (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ıç:

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

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

Veri biçimini kendiniz tasarlıyorsanı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ığı boşuna değildir). XML dünyası). Ancak UTF8'in bir dezavantajı vardır - gerekli 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 bir şekilde okumak için genellikle JDBC sürücüsünü veritabanında gerekli karakter kodlamasına yönlendirmek yeterlidir. Tam olarak nasıl - belirli sürücüye bağlıdır. Yakın geçmişten farklı olarak artık birçok sürücü bu ayarı desteklemektedir. Aşağıda bildiğim birkaç örnek var.

Köprü JDBC-ODBC

En sık kullanılan sürücülerden biridir. JDK 1.2 ve sonraki sürümlerden bir köprü, istenen kodlamaya göre kolayca yapılandırılabilir. Bu ekleyerek yapılır ek mülk charSet, veritabanına bağlantı açmak için geçirilen parametre kümesine. Varsayılan, file.encoding'dir. Şu şekilde yapılır:

// Bağlantı kurun

Linux altında Oracle 8.0.5'ten JDBC-OCI sürücüsü

Veritabanından veri alırken, bu sürücü, NLS_LANG ortam değişkenini kullanarak "kendi" kodlamasını tanımlar. 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 değil (file.encoding türünden) bir ortam değişkeni (set komutuyla ayarlanır) olması gerektiğidir. 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=Amerikan_Amerika.CL8KOI8R
Bununla ilgili bilgiler, kendisine özel olarak teşekkür edilen Sergey Bezrukov tarafından gönderildi.

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

Bu sürücü son zamanlarda Rus harfleriyle çalışmayı öğrendi. getPropertyInfo()'ya charSet özelliğini anladığını söylese de - bu bir kurgudur (en azından 07/30/2001 sürümünde). Aslında, CODEPAGEID özelliğini ayarlayarak kodlamayı ayarlayabilirsiniz. Rusça karakterler için iki değer mevcuttur - Cp866 için "66" ve Cp1251 için "C9". Örnek:

// Veritabanı bağlantı parametreleriÖzellikler connInfo = yeni Özellikler(); connInfo.put("CODEPAGEID", "66"); // Cp866 kodlaması // Bağlantı kurun Bağlantı db = DriverManager.getConnection("jdbc:DBF:/C:/MyDBFFiles", connInfo);
FoxPro DBF dosyalarınız varsa, kendi özellikleri vardır. Mesele şu ki, FoxPro, DBF oluşturulurken kullanılan kod sayfasının (0x1D uzaklığındaki 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 de her şey oldukça basit:

// Veritabanı 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)

"charSet" parametresi bu sürücü için çalışır:
// Veritabanı bağlantı parametreleriÖzellikler connInfo = yeni Özellikler(); 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);

Ancak veritabanı ve tabloları oluştururken karakter kodlamasını belirtmeyi unutmayınız. Rusça 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 ş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, hiçbir Rus kaynağı 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-ary kodlamada verir, bu nedenle standart native2ascii kod dönüştürücüyü kullanamazsınız - kendi kodunuzu yazmanız gerekir (Kod çözme programı ). Bu sorunlarla uğraşmak istemiyorsanız, kaynakları içeren hazır bir dosya alabilirsiniz (sürücülü yamalı jar - interclient.jar , ayrı kaynak sınıfları - interclient-rus.jar).

Ancak gerekli kodlama için JDBC sürücüsünü yapılandırdıktan sonra bile bazı durumlarda sorun yaşayabilirsiniz. Örneğin, JDK 1.3.x'ten JDBC-ODBC köprüsünde JDBC 2 standardının yeni harika kayan imleçlerini kullanmaya çalışırken, Rusça harflerin orada çalışmadığını çabucak öğrenebilirsiniz (updateString() yöntemi).

Bu hatayla ilgili küçük bir geçmiş var. Onu ilk keşfettiğimde (JDK 1.3 rc2 altında), BugParade() üzerine kaydettirdim. 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 sonraki 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 etme zamanı buldum - yine çalışmıyor. Anne, anne, anne... - yankı alışkanlıkla karşılık verdi. Sun'a öfkeli bir mektup yazdıktan sonra, parçalanması için Hint şubesine verdikleri yeni bir böcek () başlattılar. Kızılderililer kodla uğraştı ve her şeyin 1.4 beta3'te düzeltildiğini söylediler. Bu sürümü indirdim, altında bir test senaryosu başlattım, işte sonuç - . Görünüşe göre, sitede dağıtılan beta3 (derleme 84), son düzeltmenin (derleme 87) dahil edildiği beta3 değil. Şimdi düzeltmenin 1.4 rc1'e dahil edileceğine söz veriyorlar... Genel olarak, anlıyorsunuz :-)

Java program kaynaklarında Rusça harfler

Daha önce de belirtildiği gibi, program yürütülürken Unicode kullanılır. Kaynak dosyalar geleneksel düzenleyicilerde yazılır. Far kullanıyorum, muhtemelen favori editörünüz var. Bu düzenleyiciler dosyaları 8 bit biçiminde kaydeder; bu, yukarıdakiyle aynı mantığın bu dosyalar için de geçerli olduğu anlamına gelir. farklı versiyonlar Derleyiciler karakter dönüştürme işlemini biraz farklı gerçekleştirir. JDK 1.1.x'in önceki sürümleri, standart olmayan -J seçeneğiyle değiştirilebilen 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 tanıtıldı. Derlenmiş sınıflarda, dizeler Unicode olarak temsil edilir (daha doğrusu UTF8 formatının değiştirilmiş bir versiyonunda), bu nedenle en ilginç şey derleme sırasında olur. Bu nedenle en önemli şey kaynaklarınızın hangi kodlamada olduğunu bulmak ve derleme yaparken doğru değeri belirtmektir. Varsayılan olarak, aynı kötü şöhretli file.encoding kullanılacaktır. Derleyici çağrı örneği:

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

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 CodeGuide, büyük Rus harfi "T" yi iyi sindirmez. Yerleşik kod analizörü bu mektubu çift tırnak için alır ve bu da doğru kodun hatalı olarak algılanmasına yol açar. Bununla savaşabilirsiniz ("T" harfini "\u0422" koduyla değiştirerek), ancak bu hoş değildir. Görünüşe göre, ayrıştırıcının içinde bir yerde, karakterlerin baytlara açık bir dönüşümü kullanılır (örneğin: bayt b = (bayt)c), bu nedenle 0x0422 ("T" harfinin kodu) yerine, 0x22 kodu ( çift ​​tırnak için kod) elde edilir.

Başka bir sorun JBuilder ile ilgili, ancak bu daha çok ergonomi ile 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 açması nedeniyle bir hata () vardır. Şunlar. Rus bölgesel ayarlarınız varsa, sürekli olarak program yazarken çok rahatsız edici olan 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 hatanın giderildiği JDK 1.3.1'e geçmektir.

Yeni başlayan 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 yerine farklı bir derleyici kullanıyorsanız, karakter dönüşümünü nasıl gerçekleştirdiğine dikkat edin. Örneğin, IBM'in 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 sabit kodlanmıştır - javac'ta olduğu gibi bir kolaylık yoktur.

JavaDoc

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

  • -encoding - 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 ayarla eşleşmesi gerekir. Bu ayar atlanırsa meta etiket eklenmez.

Özellikler dosyalarındaki Rus harfleri

Özellikler dosyalarını okumak, belirli bir şekilde çalışan kaynak yükleme yöntemlerini kullanır. Aslında, okuma için, file.encoding kullanmayan Properties.load yöntemi kullanılır (ISO-8859-1 kodlaması orada kaynakta sabit kodlanmıştır), bu nedenle tek yol Rusça harfleri belirtin - "\uXXXX" biçimini ve .

Properties.save yöntemi, JDK 1.1 ve 1.2 sürümlerinde 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'de, yükleme yöntemini yansıtması için tekrar "\uXXXX" biçimine dönüştürülür.

Özellikler dosyalarınız kaynak olarak değil de normal 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.

Pekala, bu Servlet'lerin neye ihtiyaç duyulduğunun farkında olduğunuzu düşünüyorum. Değilse, önce belgeleri okumak en iyisidir. Ayrıca sadece Rus harfleriyle çalışmanın özelliklerini anlatıyor.

Peki özellikleri nelerdir? Bir 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) aracılığıyla. İlk durumda, bayt dizileri yazıyorsunuz, bu nedenle akışlara yazmak için yukarıdaki yöntemler geçerlidir. PrintWriter durumunda, set kodlamasını kullanır. Her durumda, karakterlerin sunucu tarafında doğru şekilde dönüştürülebilmesi için setContentType() yöntemi çağrılırken kullanılan kodlamanın doğru bir şekilde belirtilmesi gerekir. Bu gösterge, getWriter() çağrılmadan veya OutputStream'e ilk yazmadan önce yapılmalıdır. Örnek:

// Yanıt kodlamasını ayarla // Bazı motorların izin vermediğini unutmayın // ";" arasında boşluk bulunması ve "karakter seti" answer.setContentType("text/html;charset=UTF-8"); PrintWriter çıkışı = yanıt.getWriter(); // Kontrol edilecek kodlama adının çıktısında hata ayıklayın out.println("Kodlama: " + response.getCharacterEncoding()); ...out.close(); )

Bu, müşteriye yanıtları döndürmekle ilgilidir. Giriş parametreleriyle ne yazık ki o kadar basit değil. Giriş parametreleri, "application/x-www-form-urlencoded" MIME tipine göre tarayıcı bayt tarafından kodlanır. Aleksey Mendelev'in dediği gibi, Rusça harfler şu anda yüklü olan kodlamayı kullanan tarayıcılar tarafından kodlanıyor. Ve elbette, onun hakkında hiçbir şey söylenmiyor. 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 hangi 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. Bu özellik zaten destekleniyor en son sürümler Reçine ve Tomcat.

Bu nedenle, şanslıysanız ve Servlet 2.3 destekli bir sunucunuz varsa, her şey oldukça basittir:

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

request.setCharacterEncoding() yöntemini uygularken önemli bir incelik vardır - uygulanması gerekir önceki veri talebine yapılan ilk çağrı (örneğin request.getParameter()). İsteği sunucu uygulamasına ulaşmadan önce işleyen filtreler kullanırsanız, filtrelerden birinin istekten bazı parametreleri okuyabilmesi (örneğin yetkilendirme için) ve sunucu uygulamasında request.setCharacterEncoding() öğesinin okuma olasılığı sıfır değildir. çalışmamak.

Bu nedenle istek kodlamasını ayarlayan bir filtre yazmak ideolojik olarak daha doğrudur. Ancak, web.xml'deki filtreler zincirinde ilk olmalıdır.

Böyle bir filtreye bir örnek:

java.io'yu içe aktar*; java.util.* dosyasını içe aktarın; javax.servlet'i içe aktar*; javax.servlet.http.* dosyasını içe aktarın; public class CharsetFilter Filter uygular ( // private String kodlamasını kodlar; public void init(FilterConfig config) ServletException'ı ( // config'den oku kodlama = config.getInitParameter("requestEncoding"); // ayarlanmazsa - Cp1251'i ayarla if(encoding==null) encoding="Cp1251"; ) public void doFilter(ServletRequest isteği, ServletResponse yanıtı, sonraki FilterChain) IOException, ServletException ( request.setCharacterEncoding(encoding); next.doFilter(request, yanıt); ) public void destroy()() öğesini atar

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

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 gerekecek:

    orijinal yol kodlamalarla çalışma, 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 muhtemelen ayarlardadır. Tam olarak nerede - kullandığınız grafik kitaplığına 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 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 bir İ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=en 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 (hata numarasına bakın).

    Swing kitaplığı ile her şey daha basittir - her şey Java2D alt sistemi aracılığıyla çizilir. Standart diyaloglardaki (JOptionPane, JFileChooser, JColorChooser) yazıları Rusçaya çevirmek ç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'den 1.3 beta'ya kadar olan 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 çok tuhaf - standart yazı tiplerinde harflerin görüntüleri Unicode kodlarına göre değil, Cp1251 tablosuna (Ansi kodlaması) göre görüntülenir. Bu hata, BugParade ile . 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ünür. 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ının bir ö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. Ayrıca, Win95'in orijinal sürümünün Unicode'u desteklemeyen yazı tipleriyle birlikte geldiğine dikkat edilmelidir - bu durumda yazı tiplerini Win98 veya WinNT'den kopyalayabilirsiniz.

    Tipik hatalar veya "Sh harfi nereye gitti?"

    Mektup Ş.

    Bu soru (“Sh harfi nereye gitti?”) Yeni başlayan Java programcıları arasında oldukça sık ortaya çıkar. Bakalım en sık nereye gidiyor. :-)

    İşte tipik bir HelloWorld programı:

    public class Test ( public static void main(String args) ( System.out.println("JCUKENGSHCHZHJ"); ) )
    Uzakta kaydet verilen kod Test.java dosyasını dosyalamak için derleyin...
    C:\>javac Test.java
    ve başla...
    C:\>java Testi

    Ne oldu? W harfi nereye gitti? Buradaki bütün hile, iki hatanın karşılıklı olarak telafi edilmesidir. Metin düzeltici Far varsayılan olarak DOS kodlamasında (Cp866) bir dosya oluşturur. Javac derleyicisi, kaynağı okumak için file.encoding'i kullanır ( -encoding anahtarıyla aksi belirtilmedikçe). Ve Windows ortamı Rus bölgesel ayarlarıyla 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ı bire bir olsaydı, veri kaybı olmazdı. Ancak Cp866'daki W karakteri, Cp1251'de tanımlanmayan 152 koduna sahiptir ve bu nedenle 0xFFFD Unicode karakteriyle eşlenir. Karakterden bayta ters dönüşüm gerçekleştiğinde, bunun yerine "?" karakteri değiştirilir.

    Java.io.FileReader kullanarak bir metin dosyasından karakterleri okursanız ve sonra bunları System.out.println() kullanarak ekrana yazdırırsanız benzer bir telafiyle karşılaşabilirsiniz. Dosya Cp866 kodlamasında yazılmışsa, yine Ш harfi dışında çıktı doğru olacaktır.

    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üştürmeye - (bayt) veya (char) dikkat edin. Oldukça sık, tırmıklar 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, aşağıdaki testi deneyebilirsiniz. Herhangi bir program bir girdi işleyicisi olarak düşünülebilir. Rus harfleri aynı verilerdir, geçerler Genel davaüç işlem aşaması: 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 kaynak koduna "ABV\u0410\u0411\u0412" verisi yerine aşağıdaki test dizisini dikmeyi ve çıktısını almayı denemelisiniz. Bundan sonra, ne elde ettiğinizi görün:

    • "ABWABW" ifadesini görürseniz, kaynakların ve çıktıların derlenmesi sizin için doğru şekilde çalışıyor demektir.
    • "???ABC" (veya ilk karakterin yerine "ABC" dışında herhangi bir karakter) görürseniz üç harf), bu nedenle çıktı düzgün çalışır, ancak kaynakların derlenmesi yanlıştır - büyük olasılıkla -kodlama anahtarı belirtilmemiştir.
    • Eğer görürsen "??????" (veya ikinci üç harfin yerine "ABV" dışındaki herhangi bir karakter), çıktı sizin için çalışmıyor.

    Çıktıyı ve derlemeyi yapılandırdıktan sonra, girdiyle uğraşmak zaten kolaydır. Tüm zinciri kurduktan sonra sorunlar ortadan kalkmalıdır.

    native2ascii yardımcı programı hakkında

    Bu yardımcı program Sun JDK'nın bir parçasıdır ve kaynak metinleri ASCII'ye dönüştürmek için tasarlanmıştır. Belirtilen kodlamayı kullanarak girdi dosyasını okur ve çıktı olarak "\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 derlenmesini bekliyorsanız kaynakları işlemek için çok kullanışlıdır.

    Programı parametresiz çalıştırırsanız, standart giriş(stdin) ve diğer yardımcı programlar gibi tuşlar için bir ipucu görüntülemez. Bu, birçok insanın parametreleri belirtme gereğini bile anlamamasına yol açar (belki de belgelere bakma gücünü ve cesaretini bulmuş olanlar 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ı kurtarmak 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 geçerli olan sayfayı kullanarak, normal kodlar karakterler. Örnek:

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

    Bu yaklaşımla ilgili birkaç sorun olabilir. Örneğin, geri yüklemek için yanlış sayfa veya bazı durumlarda değişebilir. Başka bir sorun, bazı sayfaların belirsiz bayt dönüşümü yapması olabilir.<->karakter. Örneğin, sayıya göre hatanın açıklamasına bakın.

    Bu nedenle, bu yöntemi yalnızca başka hiçbir şey yardımcı olmadığında son çare olarak kullanmalısınız ve yanlış karakter dönüşümünün tam olarak nerede gerçekleştiğini açıkça hayal edin.

    Rus harfleri ve MS JVM

    Hangi nedenlerle olduğu belli değil, ancak Rus harflerini kodlamak için tüm dosyalardan yoksun, acre Cp1251 (muhtemelen dağıtımın boyutunu bu şekilde azaltmaya çalıştılar). Başka kodlamalara ihtiyacınız varsa, örneğin Cp866, uygun sınıfları CLASSPATH'e eklemeniz gerekir. Ayrıca, Sun JDK'nın en son sürümlerinden gelen sınıflar uygun değildir - Sun yapılarını uzun süredir değiştirmiştir, bu nedenle sınıfların en son sürümleri Microsoft'a uymuyor (MS hala JDK 1.1.4'ün yapısına sahiptir). Microsoft sunucusunda, prensip olarak, eksiksiz bir ek kodlama seti vardır, ancak yaklaşık 3 metre boyutunda bir dosya vardır ve sunucuları özgeçmişi desteklemez :-). Bu dosyayı indirmeyi başardım, bir kavanoz 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 dışında (örneğin, Cp866'da) Rusça kodlamada okumanız gerekiyorsa, artık standart kodlama mekanizmasını kullanabilme - uygulamaların sistem paketlerine sınıf eklemesine izin verilmez; bu durum sun.io paketidir. İki çıkış yolu vardır - ya sunucudaki dosyayı Cp1251'e (veya UTF-8'e) yeniden kodlayın ya da baytlardan Unicode'a dönüştürmeden önce, baytları istenen kodlamadan Cp1251'e dönüştürün.

    Java'nın Linux altında Ruslaştırılması

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

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

    1. GUI bileşenlerinde Kiril çıktı sorunu
    2. Kiril klavye giriş sorunu (X11'de)

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

    1. X11 normaline ayarla ttf yazı tipleri Windows NT/200'den. 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. Ekle sonraki dosya font.properties.ru'dan $Java_HOME/jre/lib dizinine

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

    Aşağıdaki konfigürasyonda 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 harfleri (crocozyabrs olarak görünür) girmenize izin vermez.

    AWT'de XIM (-> xkb) kullanarak. (bu kendi başına kötü bir şey değil, sadece dikkatli bir şekilde ele alınması gerekiyor + bazı xkb ekleri sevmiyor).

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

    Prosedür:

    1. yerel ayar ayarlanır ( /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. düzenleme (henüz yapılmadıysa) /etc/X11/XF86Config. Klavye bölümü şöyle görünmelidir:
      XkbKeycodes "xfree86" XkbTypes "default" XkbCompat "default" XkbSymbols "ru" XkbGeometry "pc" XkbRules "xfree86" XkbModel "pc101" XkbLayout "ru" XkbOptions "grp:shift_s_s_sto" ile geçiş # büyük harf kilidini aç/kapat" ohm
      not: bu xkb ayarı xrus (ve kikbd gibi diğerleri) ile uyumlu değildir ve bu nedenle onlara elveda demek zorunda kalacağız.
    3. X 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/fonts
    6. cd $JAVA_HOME/jre/lib/fontlar; 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. :-)

Sorununuz, Netbeans "konsolunun" - ve işletim sistemi konsolunun - biraz farklı şeyler olmasıdır. Özellikle, kullanılan farklı kodlamalara sahiptirler. Mevcut konsol kodlamasını Konsol API'si aracılığıyla almak en uygunudur - ancak Java bunu sağlamaz. Bu nedenle konsol kodlaması hakkında başka 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 sadece kimse tarafından okunamaz. cp866 içine 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 = new PrintStream(System.out, kodlama);

Böylece, cp866'da girdi beklemek yerine, program onu ​​çalıştıran kullanıcının herhangi bir kodlamayı belirtmesine izin verir (utf-8 varsayılan kodlamadır. NetBeans konsolu ne kullanıyorsa onu değiştirin). Programı şu şekilde çalıştırmanız gerekecek:

Java -Dconsole.encoding=cp866 ...

İlk bakışta, bu fırlatma şekli karmaşık görünüyor. Ancak genellikle "ciddi" Java programlarını çalıştırmak için her zaman bir tür toplu iş dosyası kullanılır. Bu anahtarın buna eklenmesini engelleyen nedir?

Ve unutmayın, Windows'taki konsol 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 kaydı ... java -Dconsole.encoding=windows-1251 ...

Yöntem 2

Zaten toplu iş dosyalarından bahsediyorsak, 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ı

PS

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

Öte yandan, çoğu veri dosyası 8 bitlik bir karakter temsilini temel alır. Buna metin dosyaları ve çoğu veritabanları da dahildir (en gelişmiş olanlar hariç). Ayrıca, hepsinden kötüsü, aynı baytlar şunları gösterebilir: farklı semboller(kod sayfasına bağlı olarak). Bir çakışma var - birinden diğerine nasıl dönüştürüleceği ve tam 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, bunun yerine ? karakteri gelir.

Bu arada, JDK 1.1'in bazı eski sürümlerindeki bu kod sayfası dosyaları, kayıt hatalarına ve hatta çalışma zamanı istisnalarına neden olan hatalar içerir. Örneğin, bu KOI8_R kodlamasıyla ilgilidir. Yapılacak en iyi şey, sürümü daha sonra 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, dönüşümün olduğu yerlerde kod sayfasının adını belirten ek bir parametre (String enc) belirtebilirsiniz. Bu 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 kodlama tanıtıldı. Varsayılan olarak, sisteme bağlıdır (Rus Windows için Cp1251 kodlaması kabul edilir) ve daha eski JDK'larda file.encoding sistem özelliği ayarlanarak değiştirilebilir. Aslında Sun'a göre bu özellik sistem kodlamasını yansıtır ve komut satırında değiştirilmemelidir (bkz. örneğin BugID ile ilgili yorumlar) Sayfa adı açıkça belirtilmediğinde bu kodlama kullanılır. Çünkü bu ayar tüm dönüşümler için bir ayardır, bazen bir sorunla karşılaşabilirsiniz. Örneğin, aynı ayar, Windows durumunda genellikle kabul edilemez olan konsol ekranına çıktı almak için kullanılır - orada Cp866 sayfasını kullanmanız gerekir. Bu kodlamaların bağımsız olarak belirtilmesi harika olurdu - örneğin, console.encoding, vb., ancak Sun-sheep'in henüz bu kadar önemli konulara girmediğini düşünüyorum.

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

  1. System.out.println yerine kendi sınıfınızı kullanın ve içindeki dönüşümü zaten yapın. Örneğin:
    public class Msg ( static String cp = System.getProperty("console.encoding","Cp866"); public static void mesajı(String msg) ( msg += "\n"; bayt b; deneyin ( b = msg.getBytes) (cp); ) catch(UnsupportedEncodingException e) ( // Gerekli kodlama eksikse, // 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 bunu System.setOut() ve System.setErr() aracılığıyla değiştirin. Örneğin, programlarımdaki olağan başlangıç:
    ... public static void main(String args) ( // Konsol mesajlarının çıktısını // istenen kodlama denemesinde ayarlayın ( System.setOut(new CodepagePrintStream (System.out,System.getProperty ("console.encoding","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 yeniden kodlamak için belirtilen yöntemleri kullanın sınıf Dize. 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:
    // Rusça harfleri bir nesne üzerinden kodlamada Cp866'da okuma // sadece Cp437'yi destekler String str = o.readString(); str = new String(str.getBytes("Cp437"),"Cp866"); // Rusça harfleri kaydetme // bir nesne aracılığıyla kodlamayı Cp866'da // sadece Cp437'yi destekler str = new String(str.getBytes("Cp866"),"Cp437"); o.writeString(str);
    Bu yöntemle ilgili daha fazla ayrıntı ve bununla ilgili olası sorunlar, aşağıda Karakter dönüştürme yöntemi hakkında bölümünde açıklanmıştır.
  4. Veritabanı sürücüsünü gerekli kodlamaya ayarlayı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 bir tür kodlama hakkında hiçbir fikri yoktur. Bazen bu etki için yamalanabilirler, ancak çoğu zaman bunun üzerinde çalışmanız 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 hileler 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 kodlamaya ayarlanabilir. Bu, veritabanına bir bağlantı açmak için geçirilen parametre kümesine ek bir charSet özelliği eklenerek yapılır. Varsayılan, file.encoding'dir. Şu şekilde yapılır:

    // Veritabanı bağlantı 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'ta 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ü, NLS_LANG ortam değişkenini kullanarak "kendi" kodlamasını belirler. Bu değişken bulunamazsa, kodlamanın ISO88591 olduğunu varsayar. İşin püf noktası, NLS_LANG'nin yalnızca bir ortam değişkeni olması gerektiği ve özelliklerin (file.encoding türünün) burada çalışmamasıdır. Sürücü Apache+Jserv sunucu uygulaması motorunda kullanılıyorsa, ortam değişkeni jserv.properties dosyasında ayarlanabilir:

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

Biçimi oluşturmakta özgürseniz - o zaman her şey daha kolaydır. Unicode veya UTF8 formatını kullanın - sorun olmayacaktır.

Bir veritabanı söz konusu olduğunda, elbette, bazı onaltılık biçimler kullanabilirsiniz, ancak bu her zaman kabul edilebilir değildir, çünkü Disk alanında 2 - 4 kat artış elde edecek ve kullanma yeteneğini kaybedeceksiniz. standart programlar veritabanı ile çalışın, örneğin rapor oluşturucular.

Daha önce de belirtildiği gibi, program yürütülürken Unicode kullanılır. Kaynak dosyalar geleneksel düzenleyicilerde yazılır. Far kullanıyorum, muhtemelen favori editörünüz var. Bu düzenleyiciler dosyaları 8 bit biçiminde kaydeder; bu, yukarıdakiyle aynı mantığın bu dosyalar için de geçerli olduğu anlamına gelir. Derleyicilerin farklı 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 değiştirilebilen 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 tanıtıldı. Derlenmiş sınıflarda, dizeler Unicode olarak temsil edilir (daha doğrusu UTF8 formatının değiştirilmiş bir versiyonunda), bu nedenle en ilginç şey derleme sırasında olur. Bu nedenle en önemli şey kaynaklarınızın hangi kodlamada olduğunu bulmak ve derleme yaparken doğru değeri belirtmektir. Varsayılan olarak, aynı kötü şöhretli file.encoding kullanılacaktır. Derleyici çağrı örneği:

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

Özellikler dosyalarındaki Rus harfleri.

Özellikler dosyalarını okumak, belirli bir şekilde çalışan kaynak yükleme yöntemlerini kullanır. Aslında, okuma için, file.encoding (kodlama orada sabit kodlanmıştır) kullanmayan Properties.load yöntemi kullanılır, bu nedenle Rusça harfleri belirtmenin tek yolu "\uxxxx" biçimini ve native2ascii'yi kullanmaktır. Yarar.

Properties.save yöntemi, JDK 1.1 ve 1.2 sürümlerinde 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'de, yükleme yöntemini yansıtması için tekrar "\uxxxx" biçimine dönüştürülür.

Servlet'lerde Rusça harfler.

Pekala, bu Servlet'lerin neye ihtiyaç duyulduğunun farkında olduğunuzu düşünüyorum. Değilse, önce belgeleri okumak en iyisidir. Ayrıca sadece Rus harfleriyle çalışmanın özelliklerini anlatıyor.

Peki özellikleri nelerdir? Bir Servlet bir istemciye 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 yazıyorsunuz, bu nedenle bir dosyaya yazmak için yukarıdaki yöntemler geçerlidir. PrintWriter durumunda, set kodlamasını kullanır. Her durumda, karakterlerin sunucu tarafında doğru şekilde dönüştürülebilmesi için setContentType() yöntemi çağrılırken kullanılan kodlamanın doğru bir şekilde belirtilmesi gerekir. Bu gösterge, getWriter() çağrılmadan veya OutputStream'e ilk yazmadan önce yapılmalıdır. Örnek:

public void doPost(HttpServletRequest isteği, HttpServletResponse yanıtı) ServletException, IOException(response.setContentType("text/html; charset=windows-1251")); PrintWriter çıkışı = yanıt.getWriter(); // Kontrol edilecek kodlama adının çıktısında hata ayıklayın.println("Encoding: " + response.getCharacterEncoding()); ...out.close();
Bu, müşteriye yanıtları döndürmekle ilgilidir. Giriş parametreleriyle ne yazık ki o kadar basit değil. Giriş parametreleri, "application/x-www-form-urlencoded" MIME tipine göre tarayıcı bayt tarafından kodlanır. Aleksey Mendelev'in dediği gibi, Rusça harfler şu anda yüklü olan kodlamayı kullanan tarayıcılar tarafından kodlanıyor. Ve elbette, onun hakkında hiçbir şey söylenmiyor. 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() içinde günlüğe kaydedilen bir hatadır. Ne yazık ki bu hata "Düzelmeyecek" olarak kapatıldı, bahanesiyle RFC'de bu konuyla ilgili hiçbir şey söylenmediği için hiçbir şey yapmayacağız. Ancak geliştiricilerimizin SERVLET-INTEREST posta listesindeki yazışmalarından sonra işler çığırından çıkmış gibi görünüyor. En azından dudak hizmetinin JSDK 2.3 belirtiminde bir kodlama ayarlamak için bir yöntem içermesi sözü verildi.

Bu arada kendi kaynaklarınızla yetinmek zorundasınız. Kodlamalarla çalışmanın orijinal yolu 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 etkileşim için bir standarttır. Tahmin edilebileceği gibi, bu havzada ayrıca 8 ve 16 bitlik kodlamaların çakışması 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 çoğu dize işlemi 8 bitlik karakter türünde yapılır. Prensipte bu yönde bazı ilerlemeler vardır, özellikle Windows NT için Win32 API'nin 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 (String'in JNI gösterimi) char* türünü almak ve bunun tersidir. Hemen hemen tüm JNI açıklamaları ve örnekleri bunun için GetStringUTFChars/ReleaseStringUTFChars işlev çiftini kullanır. Sinsi burjuvalar burada da bir pusu hazırladılar - bu işlevler UTF standardına göre yalnızca ASCII karakterleri (ilk 128 değer) için beklenene karşılık gelen bir bayt dizisi oluşturur. Rus harfleri yine havada. Sish karakteri, Java bayt türüyle çok iyi uyuyor, ancak boş karakter biçiminde bir aksaklık var. bayt->char* dönüştürülürken eklenmeli ve ters dönüşüm. Bunu C/C++'da yapmak elverişsizdir, bu nedenle mümkün olduğunca Java'da yapmak en iyisidir. Örnek:

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

GUI (AWT, Salıncak)

Birçoğu, Rusça harflerin yanlış çıktısını yanlış yazı tipi ayarıyla ilişkilendirir. Bana öyle geliyor ki bu, Windows 3.x'teki yoğun programlama deneyiminden kaynaklanıyor ve asıl nedenin gerçekten bu olduğu. Java'da işler daha karmaşıktır ve yazı tipleriyle nadiren ilişkilidir. Tarayıcıların belirli ayarlarıyla ilgilenmedim çü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ı? Bunun başlıca nedeni yanlış karakter dönüşümüdü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 yaptıysanız ve çıktı için Unicode yazı tipi kullanılıyorsa, programınızın doğru çalışması için çok iyi bir şans vardır.

Sorunlar hala devam ediyorsa, nerede ortaya çıktıklarını bulmanız gerekir. Uygulamayı 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 - kullandığınız grafik kitaplığına bağlıdır. AWT ise, font.properties.ru dosyasının doğru ayarı 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 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 bir İngilizce sürümse, -Duser.language=ru ayarını ayarlayarak mevcut dili ayrıca 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 diyaloglardaki (JOptionPane, JFileChooser, JColorChooser) yazıları Rusçaya çevirmek ç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'den 1.3 beta'ya kadar olan 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 çok tuhaf - standart yazı tiplerinde harflerin görüntüleri Unicode kodlarına göre değil, Cp1251 tablosuna (Ansi kodlaması) göre görüntülenir. Bu hata, BugParade ile . 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ünür. 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ının bir örneği). Bu yazı tiplerinin standart olanlardan nasıl farklı olduğu benim için net değil.

1.3rc1 sürümünden itibaren bu sorun zaten giderilmiştir, böylece JDK'yı kolayca güncelleyebilirsiniz. Ayrıca, Win95'in orijinal sürümünün Unicode'u desteklemeyen yazı tipleriyle birlikte geldiğine dikkat edilmelidir - bu durumda yazı tiplerini Win98 veya WinNT'den kopyalayabilirsiniz.

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. Bunu, örneğin şöyle yapabilirsiniz:

public static String convertToWin9x(String s) ( byte bb; try ( bb = s.getBytes("Cp1251"); ) catch(Java.io.UnsupportedEncodingException e) ( return s; ) char cb = new char; for(int i =0;i< bb.length; i++) { cb[i] = (char)(bb[i] & 0x00FF); } return new String(cb); }
Ama unutma - bu kod işe yarayacak sadece Win9x ve Sun JDK/JRE 1.2 altında.

Derleyici jikes ile 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 kaynakların kodlamasını hesaba katmaz. Aynı etki, -encoding anahtarında javac kodlaması ISO-8859-1 (Latin1) belirtilerek elde edilebilir. Aynı zamanda, kaynak koddaki Cp1251 kodlamasında Rusça karakterler yazılırsa, 0x400-0x4ff aralığı (Kiril için standart Unicode aralığı) yerine 0x80-0xff aralığına girerler. Win9x ortamında yukarıda bahsedilen aksaklık nedeniyle, Kiril standart yazı tipleri 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 değiştirirseniz, böyle bir tazminatla karşılaşabilirsiniz. Aynı zamanda, diğer şeylerin yanı sıra, varsayılan kodlama (file.encoding) de değişir - 1251 yerine 1252 olur. Bu, dosyaları okurken kodlama açıkça belirtilmemişse (ve -encoding anahtarı derleme sırasında belirtilmez), ardından Rusça harfler 0x80-0xff aralığına taşınır ve izlenim oluşturulur normal operasyon. Fark, Java.text.Collator aracılığıyla yapılan büyük/küçük harf dönüşümlerinde ve sıralamalarda görülebilir - bunlar düzgün çalışmayacaktır. Ve eğer kullanılmışlarsa dizi sabitleri- o zaman diğer platformlarda sadece krakozyably göreceksiniz.

Başka bir yol, Swing'in JDK 1.1 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'yi güncellemeyi unutmayın - IE 4.x ile gelen sürümler 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, acre Cp1251 (muhtemelen dağıtımın boyutunu bu şekilde azaltmaya çalıştılar). Başka kodlamalara ihtiyacınız varsa, örneğin Cp866, uygun sınıfları CLASSPATH'e eklemeniz gerekir. Ayrıca, Sun JDK'nın en son sürümlerinden gelen sınıflar uygun değildir - Sun yapılarını uzun süredir değiştirmiştir, bu nedenle sınıfların en son sürümleri Microsoft'a uymuyor (MS hala JDK 1.1.4'ün yapısına sahiptir). Microsoft sunucusunda, prensip olarak, eksiksiz bir ek kodlama seti vardır (sayfa, "Ek G / Ç kitaplıkları" bağlantısı), ancak orada dosya yaklaşık 3 metre boyutunda ve sunucuları özgeçmişi desteklemiyor :-) . Bu dosyayı indirmeyi başardım, bir kavanoz ile yeniden paketledim, buradan alabilirsiniz.

I18n (çıkış numaraları, tarihler vb.)

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 dil 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 bu 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 veya özellikler dosyasının adı 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 bir 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, arama aşağıdaki sırayla yapılacaktır:

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

Bu, yeni diller ve ülkeler için açıklamalar eklemeyi kolaylaştırır. Çoğu sınıf, tüm bu dahili pişirme işlemlerini kendileri halleder, bu nedenle çoğu zaman bunu bilmenize gerek yoktur.

Tarihlere gelince, 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, istenen biçim stilini ayarlamak 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österme DateFormat df = DateFormat.getDateInstance(); String s = df.format(yeni Tarih()); ... // Geçerli saati saniye olmadan görüntüleme DateFormat df = DateFormat. getTimeInstance(DateFormat.KISA); String s = df.format(yeni Tarih());

Çıktı 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 metinleri ASCII'ye dönüştürmek için tasarlanmıştır. Bu yardımcı program, parametresiz çalıştırıldığında standart girdi (stdin) alır ve diğer yardımcı programlar gibi bir anahtar ipucu yazdırmaz. Bu, birçok insanın parametreleri belirtme gereğini bile anlamamasına yol açar (belki de belgelere bakma gücünü ve cesaretini bulmuş olanlar 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ı kurtarmak 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 yaklaşımla ilgili birkaç sorun olabilir. Örneğin, kurtarma için yanlış sayfa kullanılır veya bazı durumlarda değişebilir. Başka bir sorun, bazı sayfaların belirsiz bayt dönüşümü yapması olabilir.<->karakter. Örneğin, sayıya göre hatanın açıklamasına bakın.

Bu nedenle, bu yöntemi yalnızca başka hiçbir şey yardımcı olmadığında son çare olarak kullanmalısınız ve yanlış karakter dönüşümünün tam olarak nerede gerçekleştiğini açıkça hayal edin.
Son değiştirilme tarihi: 13 Haziran 2000

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. Kesimin altında, 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 depolandığı için 2 bayt bellek kaplar.
Bu tür değişkenlerle yalnızca atama işlemleri gerçekleştirilebilir, ancak Farklı yollar. En basiti şöyle görünür:
c = "b";
Bir sembol aynı zamanda içinde yazılı olan kodu olarak da gösterilebilir. sekizli sistem hesaplaşma:
c = "\077";
077, 377'den büyük olmayan zorunlu üç basamaklı bir sayı olduğunda (=255 ondalık sistem hesaplaşma).
veya içinde onaltılık sistem hesaplaşma Aşağıdaki şekilde:
c = "\u12a4";
Ayrıca paragraf işareti, sayfa sonu vb. gibi özel karakterler de vardır. Paragraf işareti örneğin şöyle yazılır:
c = "\n";
Bunları burada listelemeye gerek yok. Gerekirse, her zaman kılavuza bakabilirsiniz.

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

Buna göre, sonuç şudur: doğru görüntü Konsoldaki Kiril karakterleri, Cp866 kodlamasında karakterleri görüntülemeniz 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 args) UnsupportedEncodingException'ı ( /*UnsupportedEncodingException oluşabilir*/
String x = "Merhaba dünya!!!"; // Ekrana yazdıracağımız dizi bu
PrintStream printStream = new PrintStream(System.out, true, "cp866");
/*Oluşturmak yeni Konu karakterleri otomatik olarak Cp866*/ biçimine 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şturun:
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ıyoruz ve voila aynı dizinde bir Hello.class dosyamız var ve ekrana “Hello, world !!!” mesajı geliyor. Cp866 kodlamasında.

Hangi kodlamanın içinde 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" - " seçeneğine gidin. Ekstra seçenekler sistemler" - " Ortam Değişkenleri”, “Sistem değişkenleri”ni bulun ve varsayılan olarak “C:\Program Files\Java\jdk1.7.0_25\bin” gibi JDK'nın yüklendiği satırı Path değişkenine ekleyin.