代码之家  ›  专栏  ›  技术社区  ›  Matthew Sielski

如何从javascript字符串中删除无效的utf-8字符?

  •  18
  • Matthew Sielski  · 技术社区  · 15 年前

    我想删除javascript字符串中所有无效的utf-8字符。我试过使用这个javascript:

    strTest = strTest.replace(/([\x00-\x7F]|[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3})|./g, "$1");

    这里描述的utf-8验证regex (删除链接) 更完整,我用同样的方式对它进行了修改,比如:

    strTest = strTest.replace(/([\x09\x0A\x0D\x20-\x7E]|[\xC2-\xDF][\x80-\xBF]|\xE0[\xA0-\xBF][\x80-\xBF]|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}|\xED[\x80-\x9F][\x80-\xBF]|\xF0[\x90-\xBF][\x80-\xBF]{2}|[\xF1-\xF3][\x80-\xBF]{3}|\xF4[\x80-\x8F][\x80-\xBF]{2})|./g, "$1");

    这两段代码似乎都允许有效的utf-8通过,但并没有从我的测试数据中过滤出任何不好的utf-8字符: UTF-8 decoder capability and stress test . 坏字符可能是通过不变的方式产生的,或者似乎删除了它们的一些字节,从而创建了一个新的无效字符。

    我不太熟悉utf-8标准,也不太熟悉javascript中的多字节,所以我不确定是否在regex中无法表示正确的utf-8,或者是否在javascript中应用了该regex。

    编辑:根据Tomalak的评论在我的regex中添加了全局标志-但是这对我仍然不起作用。根据Bobince的评论,我放弃在客户方做这件事。

    5 回复  |  直到 8 年前
        1
  •  17
  •   bobince    15 年前

    javascript字符串是本机Unicode。它们保存字符序列*而不是字节序列,因此不可能包含无效的字节序列。

    (从技术上讲,它们实际上包含了UTF-16代码单元序列,这不是完全相同的事情,但这可能不是您现在需要担心的任何事情。)

    如果出于某种原因需要,可以创建一个字符串,其中包含用作字节占位符的字符。即使用角色 U+0080 ('\x80')代表字节0x80。如果您使用UTF-8将字符编码为字节,然后错误地使用ISO-8859-1将它们解码回字符,这就是您将得到的结果。有一个专门的javascript习惯用法:

    var bytelike= unescape(encodeURIComponent(characters));
    

    再次从utf-8伪字节返回到字符:

    var characters= decodeURIComponent(escape(bytelike));
    

    (值得注意的是,这几乎是唯一一次 escape / unescape 应该永远使用函数。它们在其他程序中的存在几乎总是一个错误。)

    decodeURIComponent(escape(bytes)) 因为它的行为类似于UTF-8解码器,所以如果输入到它的代码单元序列不能作为UTF-8字节接受,则会引发错误。

    在JavaScript中,很少需要这样处理字节字符串。最好在客户端以Unicode本地工作。浏览器将处理UTF-8编码连接上的字符串(以表单提交或xmlhttpRequest的形式)。

        2
  •  22
  •   Ali    12 年前

    我使用这种简单而坚固的方法:

    function cleanString(input) {
        var output = "";
        for (var i=0; i<input.length; i++) {
            if (input.charCodeAt(i) <= 127) {
                output += input.charAt(i);
            }
        }
        return output;
    }
    

    基本上,您真正想要的是ASCII字符0-127,所以只需逐个字符重新构建字符串。如果是好炭,就留着吧-如果不是,就把它扔掉。如果卫生设施是你的目标,那就足够快了(事实上,它真的很快)。

        3
  •  8
  •   Tomalak    15 年前

    简单错误,影响大:

    strTest = strTest.replace(/your regex here/g, "$1");
    // ----------------------------------------^
    

    如果没有“global”标志,则只对第一个匹配进行替换。

    旁注:删除 不履行 一些复杂的条件,例如陷入一组特定的Unicode字符范围,您可以使用负向前看:

    var re = /(?![\x00-\x7F]|[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3})./g;
    strTest = strTest.replace(re, "")
    

    哪里 re 读为

    (?!      # negative look-ahead: a position *not followed by*:
      […]    #   any allowed character range from above
    )        # end lookahead
    .        # match this character (only if previous condition is met!)
    
        4
  •  5
  •   Dan Mantyla    8 年前

    如果您试图从javascript字符串中删除“无效字符”-_?½-,那么您可以这样处理它们:

    myString = myString.replace(/\uFFFD/g, '')
    
        5
  •  2
  •   Marcus Pope    13 年前

    我遇到了这个问题,一个非常奇怪的结果,从数据采集的数字图像。我的方案是独一无二的-使用Windows脚本宿主(wsh)和shell.application ActiveX对象,它允许获取文件夹的命名空间对象,并调用getdetailsof函数在操作系统分析后实质上返回exif数据。

    var app = new ActiveXObject("Shell.Application");
    var info = app.Namespace("c:\");
    var date = info.GetDetailsOf(info.ParseName("testimg.jpg"), 12);
    

    在windws vista和7中,结果如下:

    ?8/?27/?2011 ??11:45 PM

    所以我的方法是:

    var chars = date.split(''); //split into characters
    var clean = "";
    for (var i = 0; i < chars.length; i++) {
       if (chars[i].charCodeAt(0) < 255) clean += chars[i];
    }
    

    当然,结果是一个不包括那些问号字符的字符串。

    我知道你使用了一个完全不同的解决方案,但是我想我会发布我的解决方案,以防其他人对此有问题,并且不能使用服务器端语言方法。