我使用用户提供的输入在encodeURIComponent
函数的帮助下以编程方式构建URI。但是,当用户输入无效的unicode字符(例如U+DFFF
)时,该函数会抛出异常,并显示以下消息:
要编码的URI包含无效字符
我在MSDN上查了一下,但这并没有告诉我任何我不知道的事情。
更正此错误
- 确保要编码的字符串仅包含有效的Unicode序列。
我的问题是,在将其传递给encodeURIComponent
函数之前,有没有办法清理用户提供的输入以删除所有无效的Unicode序列?
答案 0 :(得分:5)
采用程序化方法来发现答案,唯一出现问题的范围是\ 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具有负面的外观,那么该功能将不那么难看......