如何将大型UTF-8字符串转换为ASCII?

5

我需要将大量的UTF-8字符串转换为ASCII。这个过程应该是可逆的,并且最好使用一个快速/轻量级的算法。

我应该怎么做?我需要源代码(使用循环)或JavaScript代码。(不应依赖于任何平台/框架/库)

编辑: 我理解ASCII表示形式看起来不正确,而且比其UTF-8原始格式更大(以字节计)。因为它是UTF-8原始格式的编码形式。


我对你的编辑感到困惑。现在听起来你实际想要做的是URL编码,是这样吗? - si28719e
1
我没有给你点踩。而且我也不关心UTF-8的二进制格式。 - Robin Rodricks
2
如果我不知道我在寻求什么,我甚至都不会得到几个正确的答案。(例如转义/Base64) - Robin Rodricks
1
你应该考虑采用David的答案 - encodeURI()/decodeURI()quote()/eval()更适合解决你的问题。 - Christoph
1
Jeremy,请看一下人们的评论并更新你的问题,目前标题和描述都非常错误。否则你将继续受到其他人的反对票。 - bogdan
显示剩余2条评论
10个回答

11
您可以使用 Douglas Crockford 的 json2.js 库中仅包含 ASCII 字符的引用函数。它看起来像这样:

    var escapable = /[\\\"\x00-\x1f\x7f-\uffff]/g,
        meta = {    // table of character substitutions
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        };

    function quote(string) {

// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.

        escapable.lastIndex = 0;
        return escapable.test(string) ?
            '"' + string.replace(escapable, function (a) {
                var c = meta[a];
                return typeof c === 'string' ? c :
                    '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
            }) + '"' :
            '"' + string + '"';
    }

这将产生一个有效的ASCII-only、javascript-quoted输入字符串的结果

例如:quote("Doppelgänger!") 将会是 "Doppelg\u00e4nger!"

要恢复编码,您只需对结果进行eval操作即可。

var encoded = quote("Doppelgänger!");
var back = JSON.parse(encoded); // eval(encoded);

为什么不使用除了eval()之外的其他东西?比如说,HTML实体? - Fowl
大多数情况下,您不需要为还原实现任何内容,这样会非常快。您可以使用基于正则表达式的取消引用方法,就像引用函数一样。 - fforw
或者你可以像json2.js一样,使用正则表达式验证来保护基于eval的反引号,以实现完整的JSON。 - fforw
4
请注意,严格来说这不是“转换为ASCII码”。实际上,您正在ASCII码的基础上实现自己的编码方案。这对于要求可能完全没有问题(并且在您看来似乎确实如此),但这不仅仅是简单的“转换为ASCII码”。 - Joachim Sauer
1
你可以使用JSON.parse(encoded)代替eval(encoded)(在底层实现上类似,但更安全)。 - Tracker1

8

任何可逆地转换为ASCII的UTF-8字符串已经是ASCII了。

UTF-8可以表示任何Unicode字符,而ASCII则不能。


2
ASCII不可能——当然可以!请看上面的被接受的答案。 - Robin Rodricks
6
@Jeremy:那就不要这么暗示地提出你的问题!“UTF-8转ASCII转换”听起来像是一个字符编码转换问题,而实际上你想要的是一种用ASCII字符集和已知字符转义语法表示Unicode(这与UTF-8不同)字符的方法。 - Rômulo Ceccon
1
@Pat,这是关于UTF-8最常见的误解之一。实际上,UTF-8和UTF-16具有可变的位长度,并且任何一个都可以表示任何Unicode字符。http://en.wikipedia.org/wiki/UTF-8 - Neall

5

正如其他人所说,你无法将UTF-8 text/plain转换为ASCII text/plain而不丢失数据。

你可以将UTF-8 text/plain转换为其他格式的ASCII。例如,HTML允许使用字符引用在ASCII数据文件中表示UTF-8中的任何字符。

如果我们继续以这个例子为例,在JavaScript中,charCodeAt可以帮助将字符串转换为使用HTML字符引用表示的字符串。

URLs采用了另一种方法,并在JS中实现为encodeURIComponent


3
无法将UTF-8字符串转换为ASCII,但可以将Unicode编码为与ASCII兼容的字符串。
可能你想使用Punycode - 这已经是一种标准的Unicode编码,它将所有Unicode字符编码为ASCII。对于JavaScript代码,请查看这个问题
请编辑你的问题标题和描述,以防止其他人对其进行负面评价 - 不要使用“转换”这个词,使用“编码”。

3

你的需求非常奇怪。

将UTF-8转换为ASCII会丢失有关Unicode代码点> 127(即不在ASCII中的所有内容)的所有信息。

但是,您可以尝试使用与ASCII兼容的编码(例如 UTF-7)对Unicode数据进行编码。这意味着生成的数据可以合法地解释为ASCII,但实际上它是UTF-7。


失去全部信息 - 它可以是无损的!请参考上面接受的答案。 - Robin Rodricks
UTF-7 的想法不错。 - Robin Rodricks
3
可以实现无损转换,但这时你就不再是简单的“转换为ASCII码”了,而是将其转换为基于ASCII字符集实现的某种编码方案... - Joachim Sauer

2
如果字符串使用UTF-8编码,那么它就不再是一个字符串了。它变成了二进制数据,如果你想将二进制数据表示为ASCII码,你需要将其格式化成可以用有限的ASCII字符集表示的字符串。
一种方法是使用base-64编码(C#示例):
string original = "asdf";
// encode the string into UTF-8 data:
byte[] encodedUtf8 = Encoding.UTF8.GetBytes(original);
// format the data into base-64:
string base64 = Convert.ToBase64String(encodedUtf8);

如果您想将字符串编码为ASCII数据:

// encode the base-64 string into ASCII data:
byte[] encodedAscii = Encoding.ASCII.GetBytes(base64);

很好的想法,不过我想要JS。谢谢。 - Robin Rodricks

2
function utf8ToAscii(str) {
    /**
     * ASCII contains 127 characters.
     * 
     * In JavaScript, strings is encoded by UTF-16, it means that
     * js cannot present strings which charCode greater than 2^16. Eg:
     * `String.fromCharCode(0) === String.fromCharCode(2**16)`
     *
     * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMString/Binary
     */
    const reg = /[\x7f-\uffff]/g; // charCode: [127, 65535]
    const replacer = (s) => {
        const charCode = s.charCodeAt(0);
        const unicode = charCode.toString(16).padStart(4, '0');
        return `\\u${unicode}`;
    };

    return str.replace(reg, replacer);
}

更好的方式

也可以查看JavaScript中将Uint8Array转换为字符串。您可以使用TextEncoderUint8Array

function utf8ToAscii(str) {
    const enc = new TextEncoder('utf-8');
    const u8s = enc.encode(str);

    return Array.from(u8s).map(v => String.fromCharCode(v)).join('');
}
// For ascii to string
// new TextDecoder().decode(new Uint8Array(str.split('').map(v=>v.charCodeAt(0))))

1
你想剥离所有非ASCII字符(斜杠替换为“?”等),还是在非Unicode系统中存储Unicode代码点?
首先,可以通过循环检查值是否大于128并替换它们来完成。
如果您不想使用“任何平台/框架/库”,那么您将需要编写自己的编码器。否则,我会使用JQuery的.html();

0
这里有一个函数,用于将UTF8重音符号转换为ASCII重音符号(例如àéèî等)。 如果字符串中有重音符号,则将其转换为%239。 然后在另一端,我解析字符串并知道何时有重音符号以及ASCII字符是什么。
我在JavaScript软件中使用它来向工作于ASCII的微控制器发送数据。
convertUtf8ToAscii = function (str) {
    var asciiStr = "";
    var refTable = { // Reference table Unicode vs ASCII
        199: 128, 252: 129, 233: 130, 226: 131, 228: 132, 224: 133, 231: 135, 234: 136, 235: 137, 232: 138,
        239: 139, 238: 140, 236: 141, 196: 142, 201: 144, 244: 147, 246: 148, 242: 149, 251: 150, 249: 151
    };
    for(var i = 0; i < str.length; i++){
        var ascii = refTable[str.charCodeAt(i)];
        if (ascii != undefined)
            asciiStr += "%" +ascii;
        else
            asciiStr += str[i];
    }
    return asciiStr;
}

-1

实现quote()函数可能会达到你想要的效果。我的版本在这里

你可以使用eval()来反向编码:

var foo = 'Hägar';
var quotedFoo = quote(foo);
var unquotedFoo = eval(quotedFoo);
alert(foo === unquotedFoo);

@Jeremy:其实不是 - 同样的事情,不同的实现方式;如果在发布我的答案之前看到了fforw的答案,我就不会费心了;我的版本有更多的选项(选择单引号或双引号,在必要时不转义非ASCII字符),但很可能会更慢。 - Christoph
1
失效链接 ----- - mpen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接