Использование JavaScript для усечения текста до определенного размера (8 КБ)

Я использую Zemanta API, который принимает до 8 КБ текста за вызов. Я извлекаю текст для отправки в Zemanta с веб-страниц с помощью JavaScript, поэтому я ищу функцию, которая усекает мой текст ровно на 8 КБ.

Zemanta должна выполнить это усечение самостоятельно (т. Е. Если вы отправите ей строку большего размера), но мне нужно немного переместить этот текст перед вызовом API, поэтому я хочу сохранить как можно меньшую полезную нагрузку.

Можно ли предположить, что 8 КБ текста составляет 8 192 символа, и соответственно усечь? (1 байт на символ; 1024 символа на КБ; 8 КБ = 8 192 байта / символ) Или это неточно или верно только при определенных обстоятельствах?

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

4 ответа

Решение

Если вы используете однобайтовую кодировку, да, 8192 символа =8192 байта. Если вы используете UTF-16, 8192 символа (*)=4096 байт.

(На самом деле 8192 кода, что немного отличается от суррогатов, но давайте не будем об этом беспокоиться, потому что JavaScript этого не делает.)

Если вы используете UTF-8, есть быстрый прием, который можно использовать для реализации кодера / декодера UTF-8 в JS с минимальным кодом:

function toBytesUTF8(chars) {
    return unescape(encodeURIComponent(chars));
}
function fromBytesUTF8(bytes) {
    return decodeURIComponent(escape(bytes));
}

Теперь вы можете обрезать с помощью:

function truncateByBytesUTF8(chars, n) {
    var bytes= toBytesUTF8(chars).substring(0, n);
    while (true) {
        try {
            return fromBytesUTF8(bytes);
        } catch(e) {};
        bytes= bytes.substring(0, bytes.length-1);
    }
}

(Причиной этого здесь является то, что если вы урежете байты в середине многобайтовой последовательности символов, вы получите недопустимый поток UTF-8, и decodeURIComponent будет жаловаться.)

Если это другая многобайтовая кодировка, такая как Shift-JIS или Big5, вы сами по себе.

Вы можете сделать что-то вроде этого, так как unescape частично устарела

function byteCount( string ) {
    // UTF8
    return encodeURI(string).split(/%..|./).length - 1;
}

function truncateByBytes(string, byteSize) {
    // UTF8
    if (byteCount(string) > byteSize) {
        const charsArray = string.split('');
        let truncatedStringArray = [];
        let bytesCounter = 0;
        for (let i = 0; i < charsArray.length; i++) {
            bytesCounter += byteCount(charsArray[i]);
            if (bytesCounter <= byteSize) {
                truncatedStringArray.push(charsArray[i]);
            } else {
                break;
            }
        }
        return truncatedStringArray.join('');
    }
    return string;
}

Нет, небезопасно предполагать, что 8 КБ текста - это 8192 символа, поскольку в некоторых кодировках символов каждый символ занимает несколько байтов.

Если вы читаете данные из файлов, вы не можете просто взять размер файла? Или прочитать его кусками по 8 КБ?

Как говорит Доминик, кодировка символов является проблемой - однако, если вы действительно можете убедиться, что вы будете иметь дело только с 8-битными символами (маловероятно, но возможно), или использовать 16-битные символы и ограничить себя до половины доступного пространства, то есть 4096 тогда вы можете попытаться это сделать.

Это плохая идея полагаться на JS для этого, потому что он может быть тривиально изменен или проигнорирован, и у вас есть сложности, например, с escape-символами и кодировкой. Лучше использовать JS в качестве фильтра первого шанса и использовать любой доступный для вас язык на стороне сервера (что также откроет сжатие).

Другие вопросы по тегам