Неправильная печать неанглийских символов с Java - PullRequest
0 голосов
/ 16 января 2019

Я думал, что это проблема только с Python 2, но теперь я столкнулся с подобной проблемой с Java (Windows 10, JDK8).

Мои поиски пока что приводят к небольшому разрешению.

Я прочитал из входного потока 'stdin' это значение: Viļāni. Когда я печатаю это на консоль, я получаю это: Vi????ni.

Соответствующие фрагменты кода следующие:

   BufferedReader in = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));

    ArrayList<String> corpus = new ArrayList<String>();
    String inputString = null;
    while ((inputString = in.readLine()) != null) {
        corpus.add(inputString);
    }
    String[] allCorpus = new String[corpus.size()];
    allCorpus = corpus.toArray(allCorpus);
    for (String line : allCorpus) {
        System.out.println(line);
    }

Дальнейшее расширение моей проблемы следующим образом:

Я прочитал файл, содержащий следующие 2 строки: を Sōten_Kōro Когда я читаю это с диска и выводю во второй файл, я получаю следующий вывод:

ã‚’ SÅ�ten_KÅ�ro Когда я читаю файл из stdin, используя cat testinput.txt | java UTF8Tester, я получаю следующий вывод:

??? S??ten_K??ro

Оба явно неправы. Мне нужно иметь возможность печатать правильные символы для консоли и файла. Мой пример кода выглядит следующим образом:

public class UTF8Tester {

    public static void main(String args[]) throws Exception {
        BufferedReader stdinReader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));
        String[] stdinData = readLines(stdinReader);
        printToFile(stdinData, "stdin_out.txt");

        BufferedReader fileReader = new BufferedReader(new FileReader("testinput.txt"));
        String[] fileData = readLines(fileReader);
        printToFile(fileData, "file_out.txt");

    }

    private static void printToFile(String[] data, String fileName)
            throws FileNotFoundException, UnsupportedEncodingException {
        PrintWriter writer = new PrintWriter(fileName, "UTF-8");
        for (String line : data) {
            writer.println(line);
        }
        writer.close();
    }

    private static String[] readLines(BufferedReader reader) throws IOException {
        ArrayList<String> corpus = new ArrayList<String>();
        String inputString = null;

        while ((inputString = reader.readLine()) != null) {
            corpus.add(inputString);
        }
        String[] allCorpus = new String[corpus.size()];
        return corpus.toArray(allCorpus);
    }

}

Действительно застрял здесь, и помощь будет очень признательна! Заранее спасибо. Пол

1 Ответ

0 голосов
/ 16 января 2019
  • System.in / out будет использовать набор символов Windows по умолчанию.
  • Java String будет использовать Юникод для внутреннего использования.
  • FileReader / FileWriter - это старые служебные классы, которые используют набор символов по умолчанию, поэтому они предназначены только для непереносимых локальных файлов.

Ошибка, которую вы видели, была специальным символом в виде двухбайтовой последовательности UTF-8, но каждый (специальный UTF-8) байт интерпретировался как однобайтовая кодировка по умолчанию, но со значением, отсутствующим, следовательно, дважды ? замена. * * 1 010

  • Требуется, чтобы символ вводился в System.in в кодировке по умолчанию.
  • Затем строка была преобразована из кодировки по умолчанию.
  • Для записи в файл в UTF-8 необходимо указать UTF-8.

Таким образом:

    BufferedReader stdinReader = new BufferedReader(new InputStreamReader(System.in));
    String[] stdinData = readLines(stdinReader);
    printToFile(stdinData, "stdin_out.txt");

    Path path = Paths.get("testinput-utf8.txt");
    List<String> lines = Files.readAllLines(path); // Here the default is UTF-8!

    Path path = Paths.get("testinput-winlatin1.txt");
    List<String> lines = Files.readAllLines(path, "Windows-1252");

    Files.write(lines, Paths.get("file_out.txt"), StandardCharsets.UTF_8);

Чтобы проверить, поддерживает ли ваша текущая компьютерная система японский язык:

System.out.println("Hiragana letter Wo '\u3092'."); // Either を or ?.

Видя ?, преобразование в кодировку системы по умолчанию не может быть доставлено. を это U + 3092, u-кодированный как ASCII с \ u3092.

Чтобы создать текст UTF-8 под Windows:

Files.write(Paths.get("out-utf8.txt"),
    "\uFEFFHiragana letter Wo '\u3092'.".getBytes(StandardCharsets.UTF_8));

Здесь я использую некрасивую (как правило, ненужную) маркерную спецификацию BOM \uFEFF (пробел нулевой ширины), которая позволит блокноте Windows распознавать текст в UTF-8.

...