Самый быстрый способ определить, какой символ отличается от конкретной кодировки - PullRequest
0 голосов
/ 08 июня 2018

В настоящее время у меня есть исключение, которое сообщает мне, что в полной строке содержится недопустимый символ ISO 8859-1, но я хотел бы точно определить, какой это символ.

Я мог бы проверить каждый символв строке, но это было бы весьма неэффективно.

Цель этого - сообщить пользователю инструмента, что он написал недопустимый символ, такой как €

Ввод:

Hello fri€nd

Вывод:

Error in € (index 9)

Существует ли какой-либо быстрый и эффективный способ добиться этого?

Фрагмент фактического метода:

public void writeLine(String line) throws EncodingException {
    try {
        if (!Charset.forName("ISO-8859-1" ).newEncoder().canEncode(line)) throw new EncodingException();
        bufferedWriter.write(line);
        bufferedWriter.newLine();
    } catch (IOException e) {
        e.printStackTrace();
    }   
}

Ответы [ 3 ]

0 голосов
/ 08 июня 2018

Я мог бы проверить каждый символ в строке, но это было бы совершенно неэффективно

Как вы думаете, что делает canEncode?Невозможно проверить все символы без проверки всех символов .

Если ваша строка очень длинная , вы можете увидеть некоторые преимущества от использования параллельных потоков:

final OptionalInt firstInvalidChar = line.chars()
    .parallel()
    .filter(ch -> !Charset.forName("ISO-8859-1").newEncoder().canEncode((char) ch))
    .findFirst();

if (firstInvalidChar.isPresent()) {
    throw new EncodingException(
        "The first invalid char is: " + (char) firstInvalidChar.getAsInt()
    );
}

Если бы Charset был поточно-ориентированным, вы могли бы увидеть некоторое улучшение производительности, создав отдельный экземпляр, а не партии, но, поскольку это абстрактная фабрика, не имеющая ничего в документации, мы должны предположить, чтоэто не так.

0 голосов
/ 08 июня 2018

У вас есть два варианта отслеживания ошибки кодирования в вашем фрагменте:

  • Проверьте каждый символ отдельно с помощью canEncode(char c)
  • Попробуйте настроить кодировщик так, чтобы он выдавал UnmappableCharacterException , который содержит inputLength, который сообщит вам позицию неисправного символа.Это запускается установкой CodingErrorAction на CharsetEncoder, но я не уверен, что это работает для всех кодировок.

Если ваш ввод также ISO-8859-1, иваша обработка довольно проста, тогда вы могли бы использовать это как byte[] вместо String, чтобы полностью удалить это сужающее преобразование.

0 голосов
/ 08 июня 2018

Вы можете попытаться использовать Apache Tika для определения кодировки строки.

Пример:

CharsetDetector detector = new CharsetDetector();
detector.setText(string.getBytes());
detector.detect();

Затем вы можете преобразовать вашу строку из оригиналакодировка кому-либо:

detector.getString(yourStr.getBytes(), "utf-8");
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...