如何从字符串中删除重音字符? 特别是在IE6中,我有这样的东西:

accentsTidy = function(s){
    var r=s.toLowerCase();
    r = r.replace(new RegExp(/\s/g),"");
    r = r.replace(new RegExp(/[àáâãäå]/g),"a");
    r = r.replace(new RegExp(/æ/g),"ae");
    r = r.replace(new RegExp(/ç/g),"c");
    r = r.replace(new RegExp(/[èéêë]/g),"e");
    r = r.replace(new RegExp(/[ìíîï]/g),"i");
    r = r.replace(new RegExp(/ñ/g),"n");                
    r = r.replace(new RegExp(/[òóôõö]/g),"o");
    r = r.replace(new RegExp(/œ/g),"oe");
    r = r.replace(new RegExp(/[ùúûü]/g),"u");
    r = r.replace(new RegExp(/[ýÿ]/g),"y");
    r = r.replace(new RegExp(/\W/g),"");
    return r;
};

但是IE6让我很烦,它好像不喜欢我的正则表达式。


当前回答

通过给定的测试,一个解决方案似乎要快得多:http://jsperf.com/diacritics/9

function removeDiacritics(str) {
   return str.replace(/[^A-Za-z0-9\s]+/g, function(a){
      return diacriticsMap[a] || a; 
   });
}
removeDiacritics(teste);

工作示例:http://jsbin.com/sovorute/1/edit

推理:这样做速度更快的一个原因是,我们只遍历由负正则表达式模式选择的特殊字符。最快的测试(不带in的字符串迭代)在给定文本上迭代1001,这意味着每个字符。这个函数只迭代了35次,输出了相同的结果。请记住,这将只替换地图中所指示的内容。

关于这个主题的经典文章:http://alistapart.com/article/accent-folding-for-auto-complete

来源:http://semplicewebsites.com/removing-accents-javascript,也提供了一个不错的人物地图。

其他回答

$scope.legal_name = $sanitize($scope.legal_name);
    console.log("Name before function...",$scope.legal_name);

    var str = "";
    for(var i=0; i < $scope.legal_name.length; i++) {
        var charName = $scope.legal_name.charAt(i);
        if((charName == '&') && ($scope.legal_name.charAt(i + 1) == '#')){
            var count = 0;
            var subString = "";
            while(true) {
                if(($scope.legal_name.charCodeAt(i + 2 + count) > 47) && ($scope.legal_name.charCodeAt(i + 1 + count) < 58 )) {
                    subString = subString + $scope.legal_name.charAt(i + 2 + count);
                    count++;
                } else {
                    if(subString.length > 0) {
                        var value = parseInt(subString);
                        str = str + String.fromCharCode(value);
                        i = i + 1 + count; 
                        break;
                    }
                }
            }               
        } else {
            str = str + charName;
        }
    }
    $scope.legal_name = str;
    console.log("Name After function...",str);

我发现所有这些都有点笨拙,而且我不太擅长正则表达式,所以这里有一个更简单的版本。将它翻译成你最喜欢的服务器端语言是很容易的,假设字符串已经在Unicode中:

// String containing replacement characters for stripping accents 
var stripstring = 
    'AAAAAAACEEEEIIII'+
    'DNOOOOO.OUUUUY..'+
    'aaaaaaaceeeeiiii'+
    'dnooooo.ouuuuy.y'+
    'AaAaAaCcCcCcCcDd'+
    'DdEeEeEeEeEeGgGg'+
    'GgGgHhHhIiIiIiIi'+
    'IiIiJjKkkLlLlLlL'+
    'lJlNnNnNnnNnOoOo'+
    'OoOoRrRrRrSsSsSs'+
    'SsTtTtTtUuUuUuUu'+
    'UuUuWwYyYZzZzZz.';

function stripaccents(str){
    var answer='';
    for(var i=0;i<str.length;i++){
        var ch=str[i];
        var chindex=ch.charCodeAt(0)-192;   // Index of character code in the strip string
        if(chindex>=0 && chindex<stripstring.length){
            // Character is within our table, so we can strip the accent...
            var outch=stripstring.charAt(chindex);
            // ...unless it was shown as a '.'
            if(outch!='.')ch=outch;
        }
        answer+=ch;
    }
    return answer;
}

谢谢大家 我使用这个版本并说明原因(因为我在开始时错过了这些解释,所以我试图帮助下一个读者,如果他和我一样无聊…)

备注:我想要一个高效的解决方案,所以:

只有一次regexp编译(如果需要) 每个字符串只扫描一个字符串 查找已翻译字符的有效方法 等等……

我的版本是: (里面没有新的技术技巧,只有一些精选的+解释)

makeSortString = (function() {
    var translate_re = /[¹²³áàâãäåaaaÀÁÂÃÄÅAAAÆccç©CCÇÐÐèéê?ëeeeeeÈÊË?EEEEE€gGiìíîïìiiiÌÍÎÏ?ÌIIIlLnnñNNÑòóôõöoooøÒÓÔÕÖOOOØŒr®Ršs?ߊS?ùúûüuuuuÙÚÛÜUUUUýÿÝŸžzzŽZZ]/g;
    var translate = {
"¹":"1","²":"2","³":"3","á":"a","à":"a","â":"a","ã":"a","ä":"a","å":"a","a":"a","a":"a","a":"a","À":"a","Á":"a","Â":"a","Ã":"a","Ä":"a","Å":"a","A":"a","A":"a",
"A":"a","Æ":"a","c":"c","c":"c","ç":"c","©":"c","C":"c","C":"c","Ç":"c","Ð":"d","Ð":"d","è":"e","é":"e","ê":"e","?":"e","ë":"e","e":"e","e":"e","e":"e","e":"e",
"e":"e","È":"e","Ê":"e","Ë":"e","?":"e","E":"e","E":"e","E":"e","E":"e","E":"e","€":"e","g":"g","G":"g","i":"i","ì":"i","í":"i","î":"i","ï":"i","ì":"i","i":"i",
"i":"i","i":"i","Ì":"i","Í":"i","Î":"i","Ï":"i","?":"i","Ì":"i","I":"i","I":"i","I":"i","l":"l","L":"l","n":"n","n":"n","ñ":"n","N":"n","N":"n","Ñ":"n","ò":"o",
"ó":"o","ô":"o","õ":"o","ö":"o","o":"o","o":"o","o":"o","ø":"o","Ò":"o","Ó":"o","Ô":"o","Õ":"o","Ö":"o","O":"o","O":"o","O":"o","Ø":"o","Œ":"o","r":"r","®":"r",
"R":"r","š":"s","s":"s","?":"s","ß":"s","Š":"s","S":"s","?":"s","ù":"u","ú":"u","û":"u","ü":"u","u":"u","u":"u","u":"u","u":"u","Ù":"u","Ú":"u","Û":"u","Ü":"u",
"U":"u","U":"u","U":"u","U":"u","ý":"y","ÿ":"y","Ý":"y","Ÿ":"y","ž":"z","z":"z","z":"z","Ž":"z","Z":"z","Z":"z"
    };
    return function(s) {
        return(s.replace(translate_re, function(match){return translate[match];}) );
    }
})();

我是这样用的:

var without_accents = makeSortString("wïthêüÄTrèsBïgüeAk100t");
// I let you guess the result,
// no I was kidding you : I give you the result : witheuatresbigueak100t

评论:

Tthe instruction inside it is done once (after, makeSortString != undefined) function(){...} is stored once in makeSortString, so the "big" translate_re and translate objects are stored once When you call makeSortString('something') it call directly the inside function which calls only s.replace(...) : it is efficient s.replace uses regexp (the special syntax of var translate_re= .... is in fact equivalent to var translate_re = new RegExp("[¹....Z]","g"); but the compilation of the regexp is done once for all, and the scan of the s String is done one for a call of the function (not for every character as it would be in a loop) For each character found s.replace calls function(match) where parameter match contains the character found, and it call the corresponding translated character (translate[match]) Translate[match] is probably efficient too as the javascript translate object is probably implemented by javascript with a hashtab or something equivalent and allow the program to find the translated character almost directly and not for instance through a loop on a array of all characters to find the right one (which would be awfully unefficient).

假设你知道你在做什么,我怀疑IE6没有正确地解释文件的编码,因此不能识别文件中的非ascii字符:

确保文件保存为UTF-8格式(例如) 使用Fiddler或其他工具检查web服务器是否发送正确的内容编码HTTP报头。

(虽然它“闻起来”不对,但我会考虑做排序,比如在服务器上使用一些locale感知的东西……但无论如何…)

替换变音符的一种更简单的方法。

function replaceDiacritics(str){

  var diacritics = [
    {char: 'A', base: /[\300-\306]/g},
    {char: 'a', base: /[\340-\346]/g},
    {char: 'E', base: /[\310-\313]/g},
    {char: 'e', base: /[\350-\353]/g},
    {char: 'I', base: /[\314-\317]/g},
    {char: 'i', base: /[\354-\357]/g},
    {char: 'O', base: /[\322-\330]/g},
    {char: 'o', base: /[\362-\370]/g},
    {char: 'U', base: /[\331-\334]/g},
    {char: 'u', base: /[\371-\374]/g},
    {char: 'N', base: /[\321]/g},
    {char: 'n', base: /[\361]/g},
    {char: 'C', base: /[\307]/g},
    {char: 'c', base: /[\347]/g}
  ]

  diacritics.forEach(function(letter){
    str = str.replace(letter.base, letter.char);
  });

  return str;
};