Java encode windows 1252

Java 1.6 Windows-1252 encoding fails on 3 characters

EDIT: I’ve been convinced that this question is somewhat non-sensical. Thanks to those who responded. I may post a follow-up question that is more specific.

Today I was investing some encoding problems and wrote this unit test to isolate a base repro case:

JDK 1.6.0_07 on Mac OS 10.6.2

Latin1 symmetrically encodes all 254 characters. Windows-1252 does not. The three printable characters (193, 205, 207) are the same codes in Latin1 and Windows-1252, so I wouldn’t expect any issues.

Can anyone explain this behavior? Is this a JDK bug?

2 Answers 2

In my opinion the testing program is deeply flawed, because it makes effectively useless transformations between Strings with no semantic meaning.

If you want to check if all byte values are valid values for a given encoding, then something like this might be more like it:

Note that this testing program tests inputs using the (usnigned) byte values from 1 to 255. The code in the question uses the char values (equivalent to Unicode codepoints in this range) from 1 to 255.

Try printing the actual byte arrays handled by the program in the example and you see that you’re not actually checking all byte values and that some of your «bad» matches are duplicates of others.

Running this with «Windows-1252» as the argument produces this output:

Which tells us that Windows-1252 doesn’t accept the byte values 129, 1441, 143, 144 and 157 as valid values. (Note: I’m talking about unsigned byte values here. The code above shows -127, -115, . because Java only knows unsigned bytes).

The Wikipedia article on Windows-1252 seems to verify this observation by stating this:

According to the information on Microsoft’s and the Unicode Consortium’s websites, positions 81, 8D, 8F, 90, and 9D are unused

Java writing a file as pure “windows-1252”

I have got the following Array of decimal ascii values

I want to write those values into a file as (ascii / windows-1252) characters.

As you can easily see there are some chars in my output that will not appear in the file as I would expect them to do. The code that writes my file:

So why are some special characters not correctly written to my file?

2 Answers 2

When you call Writer.write(int) you’re meant to provide a Unicode value.

So looking at your first character for example, you’ve got Unicode 146, aka U+0092. Looking at the Unicode chart for U+0080 to U+00FF, that’s the «private use 2» character. It’s not clear why you’d expect it to come out as an apostrophe.

If you’ve got the exact bytes that you want to end up in the file, you shouldn’t use a Writer at all — you should just use an OutputStream .

outputstream is abstract class. how is the write function then used? I am having similar trouble while writing chinese characters to an excel file . i built my code in a very similar way to code mentioned. and intead of OutputStreamWriter =new OutputStreamWriter(new FileOutputStream(output),»utf-8″); i used =new OutputStream(new FileOutputStream(output),»utf=8″);

i was able to built the code with this modification but the the value in excel is still gibberish

Not the answer you’re looking for? Browse other questions tagged java encoding or ask your own question.

Hot Network Questions

Subscribe to RSS

To subscribe to this RSS feed, copy and paste this URL into your RSS reader.

site design / logo © 2021 Stack Exchange Inc; user contributions licensed under cc by-sa. rev 2021.4.16.39093

By clicking “Accept all cookies”, you agree Stack Exchange can store cookies on your device and disclose information in accordance with our Cookie Policy.

Читайте также:  System windows media brush color

Кодировка по умолчанию для компилятора языка Java (Javac)

Столкнулся с одним интересным вопросом. Вводил одного своего товарища в азы программирования и столкнулся с определённой коллизией. Всегда был уверен в том, что стандартный компилятор языка Java (Javac), который поставляется в составе многих JDK, в частности в составе Oracle JDK, определяет кодировку любого Java-файла, как UTF-8, если мы не даём ему явным образом понять, что дело имеется с какой-либо другой кодировкой. Мы конечно же могли бы сделать это при помощи параметра -encoding, но никто не обязует нас этого делать, если нас устраивает то поведение, которому компилятор подчиняется по умолчанию.

И вроде бы всё работало нормально, пока я не решил попробовать сохранить Java-файл в кодировке UTF-8 с использованием маркера последовательности байтов (BOM), который явно указывает на тот факт, что наш файл закодирован именно при помощи данного стандарта кодирования. Напомню, что для кодировки UTF-8, данный специальный символ состоит из неразрывной трёхбайтовой последовательности, которую можно представить в шестнадцатиричной форме, как EF BB BF . Это конечно совершенно необязательно, да и поведение компилятора было вполне ожидаемым, так как я понимал, что он не ожидает этого символа и скорее всего не сможет определить его должным образом и выдаст соответствующую ошибку. При этом, результат немного удивил и заставил задуматься над вопросом, а действительно ли комплятор определяет нашу кодировку, как UTF-8? При попытке компиляции получил следующую ошибку:

Если транслятор знает, что мы используем UTF-8, то почему он определил наш символ, как U+00BB , а не U+FEFF , который у нас на самом деле используется? Мне кажется, что в таком случае компилятор должен был выдать ошибку типа:

Кто может объяснить подобное поведение компилятора и какую кодировку он воспринимает по умолчанию? Думаю, что вопрос интересный и было бы неплохо с этим разобраться! Благодарю всех за помощь!

1 ответ 1

Действительно, в моей системе всё содержимое файлов, которые я подавал на вход стандартному компилятору Java (Javac), воспринималось в кодировке Windows-1251, в качестве исходной. Это было выяснено экспериментальным путём и несколько раз подтверждено. Что интересно, именно эта кодировка является стандартной в моём случае, даже несмотря на то, что моя операционная система, а у меня стоит Windows 10 Enterprise x86-64 version 10.0.18363.778 (Win10 19H2 [1909] November 2019 Update) , устанавливалась с английского дистрибутива и не содержала дополнительных языковых пакетов. Кроме того, в региональных настройках у меня включена опция Beta: Use Unicode UTF-8 for worldwide language support , которая предполагает использование UTF-8 в качестве стандартной кодировки, если я правильно понял смысл этого параметра. Тем не менее, полагаю, что кодировка Windows-1251 используется по той причине, что на этапе первоначальной установки операционный системы, в качестве текущего формата времени и денежных единиц, была выбрана Россия с её параметром «Русский (Россия)».

Когда я запускал программу, которая была сохранена в кодировке UTF-8 с маркером последовательности байтов, то происходило примерно следующее. Поскольку я был уверен в том, что в качестве исходной кодировки и так будет использован UTF-8, то не стал использовать параметр -encoding и явно указывать на эту кодировку. На самом же деле файл обрабатывался в кодировке Windows-1251, что немного ввело в ступор, так как та ошибка, на которую указывал компилятор, была не совсем очевидной, если его поведение понимается ошибочно. Поскольку по умолчанию использовалась кодировка Windows-1251, представляющая собой однобайтовую кодовую страницу, то компилятор воспринимал нашу 3-байтовую последовательность в самом начале, как 3 отдельных символа, а не как один, что собственно и было задумано. Итак, последовательность EF BB BF читалась компилятором, как следующий набор символов: п»ї . К символам п и ї особых вопросов у нашего транслятора не возникло, так как эти символы могут быть частью (и даже началом) вполне корректного токена. Речь идёт об идентификаторах, которые могут состоять, в том числе и из символов различных кириллических алфавитов. А вот с правой французской кавычкой (right-pointing double angle quotation mark, » , U+00BB) дела обстоят немного иначе. Дело в том, что этот символ не может быть частью корректных лексических токенов и может использоваться, разве что, как составляющая строковой константы. Именно по этой причине, находясь почти в любом месте в коде, он вызовет ошибку error: illegal character: ‘\u00bb’ , а про другие символы и их не совсем удачные сочетания, компилятор предпочтёт позабыть до лучших времён.

Читайте также:  Утилиты сброс пароля администратора windows

Что же касается самого бага, который действительно имеет место, то он распространяется не только на UTF-8, но и на другие кодировки. К примеру, если мы используем кодировку с указанием последовательности байтов (UTF-16BE, UTF-16LE, UTF-32BE, UTF-32LE) и сам маркер последовательности для соответствующей кодировки (тот самый BOM или U+FEFF ), то можно увидеть, что компилятор всё равно не хочет его никак понимать и будет целенаправленно ругаться. Даже если мы всегда будем указывать верную кодировку и использовать параметр -encoding с соответствующим значением, то всё равно будем получать одну и ту же ошибку (разумеется в том случае, если в самом начале файла у нас будет идти BOM): error: illegal character: ‘\ufeff’ (или ‘\ufffe’ , в случае перестановки байтов местами).

Ну и выводы, которые я для себя сделал. Не стоит использовать BOM в Java-файлах, очевидно, что компилятор с ним не дружит. Всегда использовать параметр -encoding, даже в тех случаях, когда этого можно было бы избежать, так будет намного спокойнее и понятнее. А ещё я понял, что не стоит надеяться на то, что данный баг хоть когда-нибудь пофиксят. Если этого не сделали за 19 лет, то скорее всего не сделают уже никогда.

Хочу поблагодарить @SergeyGornostaev за правильную наводку.

Java — character encoding confusion on Windows

I have a simple Java program that takes in hex and converts it to ASCII. Using JDK 8, I compiled the following:

I am passing in a hex string of C0:A8:96:FE to the program. My main concern is the 0x96 value, because it is defined as a control character (characters in the range of 128 — 159).

The output when I run the program without any JVM flags is the following:

The output when I use the JVM flag -Dfile.encoding=ISO-8859-1 to set the character encoding appears to be the following:

I’m wondering why, when the character encoding is set to ISO-8859-1, I get the extra Windows-1252 characters for characters 128 — 159? These characters shouldn’t be defined in ISO-8859-1, but should be defined in Windows-1252, but it is appearing to be backwards here. In ISO-8859-1, I would think that the 0x96 character is supposed to be encoded as a blank character, but that is not the case. Instead, the Windows-1252 encoding does this, when it should properly encode it as a – . Any help here?

1 Answer 1

My guess: While the default Charset of your JVM may be «windows-1252», your System.out is actually using Unicode.

when I use the JVM flag -Dfile.encoding=ISO-8859-1 to set the character encoding

My experiments below lead me to suspect that whatever you were doing did not actually affect the character set used by System.out . I believe that in both your runs, when you thought your System.out was using «windows-1252» or «ISO-8859-1», your System.out was in fact using Unicode, likely UTF-8.

Details

Actually, you are asking about Unicode rather than ASCII. ASCII has only 128 characters.

My main concern is the 0x96 value, because it is defined as a control character (characters in the range of 128 — 159).

Actually, that range of control characters starts at 127 in Unicode (and ASCII), not 128. Code point 127 is DELETE character. So 127-159 are control characters.

First, let’s split your input string of hex codes.

Now convert each hex text into hex integer. We use that integer as a Unicode code point.

Rather than rely on some default character encoding, let’s explicitly set the Charset of our System.out . I’m no expert on this, but some web-searching found the code below where we wrap System.out in a new PrintStream while setting a Charset by its name. I could not find a way to get the Charset of a PrintStream , so I asked.

Windows-1252

Next, we do the same but for setting «windows-1252» as the Charset of our wrapped System.out . Before doing the wrapping, we verify that such a character encoding is actually available on our current JVM.

Читайте также:  Стандартное приложение для просмотра изображений windows 10 reg

Latin-1

And we can try Latin-1 as well, producing yet a different result.

Conclusion

So you can see that when hard-coding the Charset of our wrapped System.out , we do indeed see a difference. With UTF-8, we get actual characters [À], [¨], [], [þ] whereas with windows-1252 we get three funky question mark characters and one regular question mark, [�], [�], [?], [�] . Remember that we added the square brackets in our code.

This behavior of my code matches my expectations, and apparently meets yours as well. Two of those four hex/decimal integer numbers are letters in Unicode while none of them are letters in Windows 1252 character set nor in Latin-1. The only mysterious thing to me is that the hex 96 decimal 150 number has two different representations, an empty space with UTF-8 while a question mark with windows-1252, and then a funky-question-mark under Latin-1.

Conclusion: Your System.out is not using the Charset that you think it is using. I suspect that while the JVM’s default Charset of your JVM may be named «windows-1252», your System.out is actually the Unicode character set, likely with UTF-8 encoding.

Note to the reader: If unfamiliar with character sets and character encoding, I recommend the fun and easy-reading post, The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!).

Encoding cp1252

When I try the following in Java:

I get cp1252 as the encoding.

Is there a way to know where this value is coming from? (Like Environment variables or something)

I would like to print the value of encoding on command prompt using some command like systeminfo on Windows XP.

5 Answers 5

cp1252 is the default encoding on English installations of MS Windows (what Microsoft refers to as ANSI). Java by default will take the system locale as its default character encoding. What this means is system dependent. In general I don’t like to rely on default encodings. If I know my text will be pure ASCII I ignore it — otherwise I set the encoding explicitly when instantiating InputStreamReader , OutputStreamWriter , String etc or calling getBytes .

Note that cp1252 is not the default encoding on the Windows command prompt. That is the even older cp437, which you can see (and change) using the chcp command.

That value is, on Windows at least, the legacy codepage used for non-Unicode text. It’s what the OS converts strings to and from when you use the old ANSI APIs. For any newer program it should have no effect (that being said, I still see enough programs that use the A and not the W variants of API functions, sadly).

For you Java program none of that should matter, as Java uses Unicode exclusively. If you want to write or read text files in the system’s codepage, then you’ll need it, however.

For the command prompt, however, that encoding is of no significant value, as the console by default uses the OEM encoding which mimics the one of the DOS ages (850 or 437 is pretty common).

Since this doesn’t really have anything to do with Java, you could just opt to use a WSH script:

See also the chcp command; you may want to read up on how encoding works on the Windows command prompt (some links in this blog post).

As far as I have discovered, this is the encoding of your java source file, your output will change once you change its text file encoding. On eclipse, change it from Resource property (Alt+Enter or Right click on that file, go to Resource). Change text file encoding from cp1252 to something else, say UTF-8, woo. Your output won’t be cp1252 any longer..

I believe this encoding is set by the JVM so it wouldn’t make sense to retrieve it from outside

Оцените статью