0

"Как вычислить длину строки Java в UTF-8 без её кодирования?"

11

Заголовок: Как определить длину бинарного представления строки в кодировке UTF-8 без ее генерации?

Текст вопроса: Здравствуйте, я ищу способ получить длину бинарного представления строки в кодировке UTF-8 с помощью стандартной библиотеки Java (любая версия), не создавая при этом само закодированное значение.

Например, мне нужно найти эффективный способ сделать то же самое, что и данный код:

"some really long string".getBytes("UTF-8").length

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

2 ответ(ов)

0

Ваша ситуация вполне распространена, и подход, который вы предложили, является вполне разумным. Использование CharsetEncoder для многократной записи в один и тот же временный буфер позволяет эффективно управлять буферизацией и избегать ненужных выделений памяти.

Ваш метод getEncodedLength корректно обрабатывает кодирование символов из CharBuffer с помощью заданного кодировщика. Кроме того, он правильно обрабатывает случаи, когда кодировщик выдает ошибку или когда буфер переполняется. Использование outputBuffer.clear() после каждой итерации гарантирует, что вы будете перезаписывать буфер, а не накапливать данные.

Дополнительно, вы производите финальную очистку с помощью метода flush, что также является хорошей практикой для завершения процесса кодирования.

Вот ваш код с комментариями для большей ясности:

public int getEncodedLength(CharBuffer src, CharsetEncoder encoder)
    throws CharacterCodingException
{
    // Проверяем, есть ли оставшиеся символы для кодирования
    if (!src.hasRemaining())
        return 0;

    // Создаем временный буфер для кодирования
    final ByteBuffer outputBuffer = ByteBuffer.allocate(1024);

    // Итеративный процесс кодирования
    int bytes = 0;
    CoderResult status;
    do
    {
        // Кодируем символы из CharBuffer в ByteBuffer
        status = encoder.encode(src, outputBuffer, true);
        if (status.isError())
            status.throwException(); // Обрабатываем ошибки кодирования

        // Суммируем количество записанных байтов
        bytes += outputBuffer.position();

        // Очищаем буфер для повторного использования
        outputBuffer.clear();
    }
    while (status.isOverflow()); // Продолжаем, пока буфер переполнен

    // Завершаем кодирование оставшегося состояния
    status = encoder.flush(outputBuffer);
    if (status.isError() || status.isOverflow())
        status.throwException(); // Обрабатываем финальные ошибки

    // Добавляем количество записанных байтов после flush
    bytes += outputBuffer.position();

    return bytes; // Возвращаем общее количество закодированных байтов
}

public int getUtf8Length(String str) throws CharacterCodingException
{
    return getEncodedLength(CharBuffer.wrap(str),
        Charset.forName("UTF-8").newEncoder());
}

Ваш метод getUtf8Length прекрасно инкапсулирует вызов getEncodedLength, что делает его удобным для использования. В целом, данный подход демонстрирует хорошую практику работы с кодировками и буферами в Java.

0

Вы можете перебрать строку следующим образом:

/**
 * Устаревший метод: не поддерживает суррогатные символы.
 */
@Deprecated
public int countUTF8Length(String str) {
    int count = 0;
    for (int i = 0; i < str.length(); ++i) {
        char c = str.charAt(i);
        if (c < 0x80) {
            count++;
        } else if (c < 0x800) {
            count += 2;
        } else {
            throw new UnsupportedOperationException("ещё не реализовано");
        }
    }
    return count;
}

Имейте в виду, что данный код устарел и не учитывает суррогатные пары, которые используются для представления символов Unicode, находящихся за пределами базовой многобайтовой плоскости. Для корректного подсчета байтов в UTF-8 нужен более сложный подход, который будет учитывать все возможные символы. Рекомендуется использовать стандартные библиотеки Java для обработки строк, такие как getBytes("UTF-8"), чтобы избежать подобных проблем.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь