Консоль не принимает русские символы на ввод
Проблема с вводом через cmd: пишу примитивную java программу для теста кодировок(поймет ли русские символы). Код следующий:
import java.util.Scanner;
public class App {
public static void main(String[] args) {
System.out.println("Написано однажды, работает везде");
Scanner console = new Scanner(System.in);
System.out.print("Введите свое имя: ");
System.out.println("Введенное имя: " + console.nextLine());
}
}
И получаю следующий результат:
C:\>java App
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8
Написано однажды, работает везде
Введите свое имя: Денис
Введенное имя:
То есть русские буквы терминал понимает, а вот принять на ввод их отказывается, иначе были бы хоть знаки вопроса.
Пытался ответить Nowhere Man, но не дает из-за рейтинга, потому дополняю вопрос. Строка Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8 появляется, если лезть в переменные среды и указать системную переменную JAVA_TOOL_OPTIONS (где-то прочитал, что оно должно помочь). Для дальнейших тестов переменную эту я удалил. Так же была снята галка в региональных настройка "бета-версия:использовать юникод(utf-8)". Проведя аналогичные опыты получил следующее:
Ответы (2 шт):
Удалось воспроизвести проблему, описанную в исходном вопросе, то есть, в консоли Win 10 Pro при установке кодовой страницы chcp 65001
будет получена "битая" строка байт, содержащая нули вместо кирилличных символов.
В моём случае нормальный вывод получался при использовании одинаковых кирилличных кодировок для ввода и вывода -- либо Win-1251, либо CP866.
Немного исправленный код:
import java.util.*;
import java.util.stream.*;
public class App2 {
public static void main(String[] args) throws Exception {
final String enc = System.getProperty("file.encoding");
System.out.println(Locale.getDefault() + "/" + enc);
System.out.println("привет");
Scanner in = new Scanner(System.in, enc);
String input;
while(!"exit".equalsIgnoreCase(input = in.nextLine())) {
System.out.println("> '" + input + "': " + hexBytes(input.getBytes(enc)));
}
System.out.println("----");
}
private static String hexBytes(byte ... arr) {
return IntStream.range(0, arr.length)
.map(i -> Byte.toUnsignedInt(arr[i]))
.mapToObj(Integer::toHexString)
.collect(Collectors.joining(" ", "[", "]"));
}
}
Вывод (Windows-консоль CMD):
F:\SO>chcp 65001
Active code page: 65001
F:\SO>java App2
en_US/UTF-8
привет
Привет!
> ' !': [0 0 0 0 0 0 21]
одни нули...
> ' ...': [0 0 0 0 20 0 0 0 0 2e 2e 2e]
exit
----
F:\SO>chcp 1251
Active code page: 1251
F:\SO>java App2
en_US/UTF-8
привет
Привет!
> '??????!': [ef bf bd ef bf bd ef bf bd ef bf bd ef bf bd ef bf bd 21]
пока
> '????': [ef bf bd ef bf bd ef bf bd ef bf bd]
exit
----
F:\SO>java -Dfile.encoding=windows-1251 App2
en_US/windows-1251
привет
Привет!
> 'Привет!': [cf f0 e8 e2 e5 f2 21]
всё ОК!
> 'всё ОК!': [e2 f1 b8 20 ce ca 21]
exit
----
F:\SO>chcp 866
Active code page: 866
F:\SO>java -Dfile.encoding=windows-1251 App2
en_US/windows-1251
привет
Привет!
> '?аЁў?в!': [8f e0 a8 a2 a5 e2 21]
exit
----
F:\SO>java -Dfile.encoding=cp866 App2
en_US/cp866
привет
Привет!
> 'Привет!': [8f e0 a8 a2 a5 e2 21]
exit
----
При запуске той же программы в консоли mintty
(GitBash), результаты значительно отличались, например, при выборе UTF-8:
- строки в программе не выводились корректно
- строка, введённая в сканнере, всегда была представлена в одной и той же кодировке
- нормальный вывод получался только в Win-1251
nowhereman@nowhere MINGW64 /f/SO
$ java App2
en_US/UTF-8
▒▒▒▒▒▒
Привет!
> '▒▒▒▒▒▒!': [d0 9f d1 80 d0 b8 d0 b2 d0 b5 d1 82 21]
exit
----
nowhereman@nowhere MINGW64 /f/SO
$ java -Dfile.encoding=cp866 App2
en_US/cp866
▒▒▒▒▒▒
Привет!
> '?▒?▒???????▒!': [d0 9f d1 80 d0 b8 d0 b2 d0 b5 d1 82 21]
exit
----
nowhereman@nowhere MINGW64 /f/SO
$ java -Dfile.encoding=windows-1251 App2
en_US/windows-1251
▒▒▒▒▒▒
Привет!
> 'Привет!': [d0 9f d1 80 d0 b8 d0 b2 d0 b5 d1 82 21]
exit
----
Разобрался. Вся проблема была из-за моего непонимания того, как это все работает "под капотом". Суть такова: 1). Файл имеет свою кодировку, именно этот момент мы и проговариваем в консоли тогда, когда пишем следующее:
java -Dfile.encoding=UTF-8 App.java
То есть дословно: "открой файл с кодировкой utf-8" 2). Консоль имеет свою кодировку, которую мы и указываем через chcp. Данная кодировка не имеет никакого отношения к открытию файла, но имеет отношение к кодировке вводимых данных, а имеенно здесь можно указать как "windows-1251", так и "cp866"(вопрос с 65001 я так и не решил) 3). После ввода данных они узодят в jvm на scanner, который работает по дефолту с utf-8(если я путаю, то прошу поправить) и здесь уже следует проговорим Scannerу какую кодировку мы ему подсовываем, а подсоовываем мы ему кодировку из консоли. В моем случае windows-1251:
Scanner console = new Scanner(System.in, "Windows-1251");
И получаем результат:
c:\>chcp 1251
Текущая кодовая страница: 1251
c:\>java -Dfile.encoding=UTF-8 App.java
Написано однажды, работает везде
Введите свое имя: Денис
Введенное имя: Денис
Прошу поправить, если я где-то был не точен в своих суждениях
Всем спасибо за помощь