【问题标题】:encodeURIComponent throws an exceptionencodeURIComponent 抛出异常
【发布时间】:2013-06-01 02:11:29
【问题描述】:

我正在使用用户提供的输入在encodeURIComponent 函数的帮助下以编程方式构建一个URI。但是,当用户输入无效的 unicode 字符(例如U+DFFF)时,该函数会抛出异常并显示以下消息:

要编码的 URI 包含无效字符

我在 MSDN 上查到了这个,但这并没有告诉我任何我不知道的事情。

纠正这个错误

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

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

【问题讨论】:

  • 为什么不直接捕获错误?去除无效字符会为您提供一些有用的东西吗?
  • @ShadowCreeper 不幸的是,根据我的要求(我无法控制),我必须删除无效字符。
  • 然后您可以获得所有可接受字符的列表并执行urlString.replace( /[^-_.a-zA-Z0-9etc]/g, '' ); 我不确定您是否可以执行/[\x1000-\xFFFF]/g 之类的操作。
  • 这可能会有所帮助:regular-expressions.info/javascript.html
  • 如果我能弄清楚 encodeURIComponent 认为哪些字符是有效的,我很乐意这样做。

标签: javascript unicode uri encodeuricomponent


【解决方案1】:

采用程序化方法来发现答案,唯一出现问题的范围是 \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 具有负面的后视功能,那么该函数将不那么丑陋...

【讨论】:

  • 顺便说一句,stripUnmatchedSurrogates 在现代浏览器中可能看起来像 function stripUnmatchedSurrogates(string) { return string.replace(/[\u{D800}-\u{DFFF}]/gu, ''); },其中支持 /u 标志
猜你喜欢
  • 2013-05-24
  • 2011-05-30
  • 1970-01-01
  • 2011-02-25
  • 2012-01-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多