javascript encodeURIComponent引发异常

b5lpy0ml  于 2023-05-27  发布在  Java
关注(0)|答案(2)|浏览(200)

我在encodeURIComponent函数的帮助下使用用户提供的输入以编程方式构建了一个URI。但是,当用户输入无效的unicode字符(如U+DFFF)时,函数会抛出异常,并显示以下消息:
要编码的URI包含无效字符
我在MSDN上查了这个,但这并没有告诉我任何我不知道的事情。
为了纠正这个错误

  • 确保要编码的字符串仅包含有效的Unicode序列。

我的问题是,有没有一种方法可以在将用户提供的输入传递给encodeURIComponent函数之前对其进行清理,以删除所有无效的Unicode序列?

sdnqo3pr

sdnqo3pr1#

采用程序化的方法来发现答案,唯一出现任何问题的范围是\ud800-\udfff,即高和低替代项的范围:

for (var regex = '/[', firstI = null, lastI = null, i = 0; i <= 65535; i++) {
    try {
        encodeURIComponent(String.fromCharCode(i));
    }
    catch(e) {
        if (firstI !== null) {
            if (i === lastI + 1) {
                lastI++;
            }
            else if (firstI === lastI) {
                regex += '\\u' + firstI.toString(16);
                firstI = lastI = i; 
            }
            else {
                regex += '\\u' + firstI.toString(16) + '-' + '\\u' + lastI.toString(16);
                firstI = lastI = i; 
            }
        }
        else {
            firstI = i;
            lastI = i;
        }        
    }
}

if (firstI === lastI) {
    regex += '\\u' + firstI.toString(16);
}
else {
    regex += '\\u' + firstI.toString(16) + '-' + '\\u' + lastI.toString(16);
}
regex += ']/';
alert(regex);  // /[\ud800-\udfff]/

然后我用一个简单的例子证实了这一点:

for (var i = 0; i <= 65535 && (i <0xD800 || i >0xDFFF ) ; i++) {
    try {
        encodeURIComponent(String.fromCharCode(i));
    }
    catch(e) {
        alert(e); // Doesn't alert
    }
}
alert('ok!');

这符合MSDN所说的,因为实际上所有的Unicode字符(甚至是有效的Unicode“非字符”)除了代理之外都是有效的Unicode序列。
你确实可以过滤掉高低代理,但是当在高低对中使用时,它们就变得合法了(因为它们的使用方式是为了允许Unicode扩展(大幅)超过其原始最大字符数):

alert(encodeURIComponent('\uD800\uDC00')); // ok
alert(encodeURIComponent('\uD800')); // not ok
alert(encodeURIComponent('\uDC00')); // not ok either

所以,如果你想采取简单的路线并阻止代理,这只是一个问题:

urlPart = urlPart.replace(/[\ud800-\udfff]/g, '');

如果您想在允许代理对(合法序列,但很少需要字符)的同时去除不匹配(无效)的代理,您可以执行以下操作:

function stripUnmatchedSurrogates (str) {
    return str.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])/g, '').split('').reverse().join('').replace(/[\uDC00-\uDFFF](?![\uD800-\uDBFF])/g, '').split('').reverse().join('');
}

var urlPart = '\uD801 \uD801\uDC00 \uDC01'
alert(stripUnmatchedSurrogates(urlPart)); // Leaves one valid sequence (representing a single non-BMP character)

如果JavaScript有负的lookhind,函数就不会那么丑陋了。

c0vxltue

c0vxltue2#

String.prototype.toWellFormed()方法返回一个字符串,其中源字符串的所有 *lone代理 * 都被Unicode替换字符U+FFFD替换。

相关问题