Стандартное кодирование ввода Java Windows cmd, Netbeans - PullRequest
0 голосов
/ 20 февраля 2019

Как вы знаете, InputStreamReader прочитает предоставленный InputStream и расшифрует его байты в символы.Если не указан charset, он будет использовать кодировку по умолчанию .

Мы можем проверить эту кодировку по умолчанию с помощью java.nio.charset.Charset.defaultCharset().displayName().

Дело 1 .Мой CMD для Windows использует cp850, но отчеты Java windows-1252.Можно доказать, что введя символ ó, System.in.read() сообщит 162, как и ожидалось.InputStreamReader, однако, не сможет его декодировать, так как он ожидает выполнения windows-1252, показывая ¢ (это 162-й windows-1252 символ).

Case 2 .В Windows мой интегрированный терминал Netbeans использует windows-1252, но Java сообщает UTF-8.Опять же, это может быть доказано, набрав символ ó и System.in.read() сообщит 243, как и ожидалось.InputStreamReader, однако, не сможет его декодировать, так как он ожидает выполнения UTF-8, показывая (код 65533).

Случай 3 .Моя машина Debian использует UTF-8 везде, в терминалах GNOME и Netbeans.При вводе символа ó, System.in.read() сообщит о двух байтах 195 и 161, которые соответствуют представлению UTF-8 этого символа.InputStreamReader покажет ó, как и ожидалось.

Что я хочу? Есть ли способ правильно определить используемую кодировку фактическую , чтобы я мог читать символыиз командной строки (в Windows CMD и Netbeans в Windows) без какого-либо особого случая?

Большое спасибо.

План B : Случай 2 может быть решен изменив кодировку файлов Netbeans на UTF-8 (и он также будет обрабатывать файлы UTF-8, что IDE должна делать в 2019 году).Вариант 1 можно решить, изменив кодовую страницу на UTF-8, но я не смог заставить это работать.

Вы можете использовать следующую программу для тестирования этих случаев.Введите одни и те же символы дважды и сравните вывод.

import java.io.*;
import java.nio.charset.Charset;

public class Prova2 {
    public static void main(String[] args) throws Exception {
        int b;

        System.out.println("Charset.defaultCharset: " + Charset.defaultCharset().displayName());
        System.out.println("I will read the next bytes: ");
        while ((b = System.in.read()) != '\n') {
            System.out.println("I have read this byte: " + b + " (" + (char) b + ")");
        }
        System.out.println("I will read the next chars: ");
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        while ((b = br.read()) != '\n') {
            System.out.println("I have read this char: " + b + " (" + (char) b + ")");
        }
        System.out.println("Thank you.");
    }

}

1 Ответ

0 голосов
/ 25 февраля 2019

Есть ли способ правильно определить фактическую используемую кодировку, чтобы я мог читать символы из командной строки без какого-либо особого случая?

В Windows вы можете обнаружить (илидаже установлено) кодовая страница, используемая при чтении символов из командной строки с использованием JNA .Однако в этом нет необходимости, если для получения ввода с консоли используется альтернативный подход:

  • Вместо чтения из System.in используйте System.console для захвата ввода пользователя.Это позволяет обрабатывать отправленный текст как String, а не byte с или char с.Это обеспечивает доступ ко всем методам String для интерпретации ввода с консоли в виде байтов, символов или данных UTF-8.
  • При таком подходе крайне важно установить подходящую кодовую страницу перед отправкой ввода из командной строки.,Например, если вы отправляете русские символы, тогда установите кодовую страницу 1251, используя chcp 1251.

С помощью этого подхода можно получить пользовательский ввод всего двумя строками кода:

Console console = System.console();
String userInput = console.readLine();

Случай 2. В Windows мой интегрированный терминал Netbeans использует windows-1252 ...

Не тратьте время на попытки заставить консольный ввод работать в NetBeans.System.console() вернет ноль, и его консоль не может быть настроена.Я подозреваю, что подобные ограничения существуют в других IDE.В любом случае, тестирование в NetBeans не дает значимых преимуществ.Просто сконцентрируйтесь на тестировании из командной строки.

Случай 2 можно решить, изменив кодировку файлов Netbeans на UTF-8 ...

Используя приведенный ниже подход,настройка проекта Кодировка не имеет значения.Он будет работать независимо от того, установлена ​​ли кодировка Windows-1252 или UTF-8.

Примечания:

  • Я тестировал только на Windows, но код должен работать на других платформах, покаконсольная среда настроена правильно.(Насколько я знаю, использование chcp относится только к Windows.)
  • Как и вы, я не смог заставить chcp 65001 работать на ввод Unicode.Просто сконцентрируйтесь на том, чтобы входные данные могли быть успешно прочитаны с использованием подходящей кодовой страницы.Например, при тестировании с символами, упомянутыми в OP (ó и ¢), будет работать любая кодовая страница, поддерживающая эти два символа.Например: 437, 850, 1252 и т. Д. Если приложение отображает символы, которые были отправлены правильно, все будет хорошо (и наоборот).

Вот код, который в основном состоит из отображенияконсольный вход:

package prova3;

import java.io.Console;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.stream.Collectors;

public class Prova3 {

    public static void main(String[] args) throws UnsupportedEncodingException {

        Console console = System.console();
        if (console == null) {
            System.out.println("System.console() return null.");
            System.out.println("If you are trying to run from within your IDE, use the command line instead.");
            return;
        }
        System.out.println("Enter some characters...");
        String userInput = console.readLine();
        System.out.println("User input:  " + userInput + " [String length: " + userInput.length() + ", chars: " + userInput.toCharArray().length + ", bytes: " + userInput.getBytes(StandardCharsets.UTF_8).length + "]");
        System.out.println("codepoints:  " + userInput.codePoints().boxed().map(n -> "x" + Integer.toHexString(n) + " (" + n + ")").collect(Collectors.toList()).toString());
        System.out.println("UTF-8 bytes: " + getBytesList(userInput));
    }

    static String getBytesList(String userInput) throws UnsupportedEncodingException {
        StringBuilder byteList = new StringBuilder("[");
        for (int i = 0; i < userInput.length(); i++) {
            byte[] bytes = userInput.substring(i, i + 1).getBytes(StandardCharsets.UTF_8);
            for (int j = 0; j < bytes.length; j++) {
                byteList.append(Character.forDigit((bytes[j] >> 4) & 0xF, 16))
                        .append(Character.forDigit((bytes[j] & 0xF), 16));
                if (j < bytes.length - 1) {
                    byteList.append(" ");
                }
            }
            if (i < userInput.length() - 1) {
                byteList.append(", ");
            }
        }
        byteList.append("]");
        return byteList.toString();
    }
}

chcp

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...