使用JavaScript执行带/不带重音字符的文本匹配

Phi*_*lip 23 javascript string collation non-ascii-characters

我正在使用基于AJAX的查找来查找用户在文本框中搜索的名称.

我假设数据库中的所有名称都将被音译为欧洲字母表(即没有西里尔语,日语,中文).但是,名称仍将包含重音字符,例如ç,ê甚至č和ć.

像"Micic"这样的简单搜索与"Mičić"不匹配 - 而且用户的期望是它会.

AJAX查找使用正则表达式来确定匹配.我已使用此函数修改了正则表达式比较,以尝试匹配更多重音字符.但是,它有点笨拙,因为它没有考虑到所有角色.

function makeComp (input)
{
    input = input.toLowerCase ();
    var output = '';
    for (var i = 0; i < input.length; i ++)
    {
        if (input.charAt (i) == 'a')
            output = output + '[aàáâãäåæ]'
        else if (input.charAt (i) == 'c')
            output = output + '[cç]';
        else if (input.charAt (i) == 'e')
            output = output + '[eèéêëæ]';
        else if (input.charAt (i) == 'i')
            output = output + '[iìíîï]';
        else if (input.charAt (i) == 'n')
            output = output + '[nñ]';
        else if (input.charAt (i) == 'o')
            output = output + '[oòóôõöø]';
        else if (input.charAt (i) == 's')
            output = output + '[sß]';
        else if (input.charAt (i) == 'u')
            output = output + '[uùúûü]';
        else if (input.charAt (i) == 'y')
            output = output + '[yÿ]'
        else
            output = output + input.charAt (i);
    }
    return output;
}
Run Code Online (Sandbox Code Playgroud)

除了这样的替代功能外,还有更好的方法吗?也许是为了"去除"被比较的字符串?

Tak*_*Isy 30

有一种方法可以""消除"被比较的字符串",而无需使用替换函数列出您要删除的所有重音...

这是我可以考虑从字符串中删除重音符号(和其他变音符号)的最简单的解决方案.

看到它的实际效果:

var string = "Ça été Mi?i?. ÀÉÏÓÛ";
console.log(string);

var string_norm = string.normalize('NFD').replace(/[\u0300-\u036f]/g, "");
console.log(string_norm);
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你.

  • 这当然是一种很好的、​​现代的方法。请记住,对此不支持 IE 或 Safari &lt; 10,因此您需要对其进行填充。它也不是一个微不足道的polyfill(虽然不是很大),所以如果你有一个对大小敏感的构建并且需要在旧浏览器上运行它可能不是最好的选择。当然,这种担忧一天比一天变得不那么重要。 (3认同)
  • 完美-轻松解决了我的用例,谢谢 (2认同)
  • 这是一个很好的解决方案。谢谢,您为我节省了数小时的痛苦。 (2认同)
  • 这将消除重音,很好。是否有类似的方法来转换 ł -&gt; l、ß -&gt; ss、æ -&gt; ae 等,或者应该通过为每个字符编写单独的替换来完成? (2认同)

Jos*_*bou 11

来到这个老线程,并认为我会尝试快速功能.在函数replace()调用时,我依赖于管道分隔的OR设置变量的排序.我的目标是使用标准的正则表达式实现javascript的replace()函数尽可能多地使用,以便重处理可以在低级别的浏览器优化空间中进行,而不是在昂贵的javascript char-by-char比较中进行.

这根本不科学,但是当我把这个线程中的其他函数插入我的自动完成时,我的旧华为IDEOS安卓手机很慢,而这个功能拉链:

function accentFold(inStr) {
  return inStr.replace(
    /([àáâãäå])|([ç??])|([èéêë])|([ìíîï])|([ñ])|([òóôõöø])|([ß])|([ùúûü])|([ÿ])|([æ])/g, 
    function (str, a, c, e, i, n, o, s, u, y, ae) {
      if (a) return 'a';
      if (c) return 'c';
      if (e) return 'e';
      if (i) return 'i';
      if (n) return 'n';
      if (o) return 'o';
      if (s) return 's';
      if (u) return 'u';
      if (y) return 'y';
      if (ae) return 'ae';
    }
  );
}
Run Code Online (Sandbox Code Playgroud)

如果你是一个jQuery开发者,这里有一个使用这个函数的简单例子; 你可以使用:icontains与你使用的方式相同:在选择器中包含:

jQuery.expr[':'].icontains = function (obj, index, meta, stack) {
  return accentFold(
    (obj.textContent || obj.innerText || jQuery(obj).text() || '').toLowerCase()
  )
    .indexOf(accentFold(meta[3].toLowerCase())
  ) >= 0;
};
Run Code Online (Sandbox Code Playgroud)


Jam*_*mes 6

我认为没有更容易的"消除"方法,但你的替代可以更加简化:

var makeComp = (function(){

    var accents = {
            a: 'àáâãäåæ',
            c: 'ç',
            e: 'èéêëæ',
            i: 'ìíîï',
            n: 'ñ',
            o: 'òóôõöø',
            s: 'ß',
            u: 'ùúûü',
            y: 'ÿ'
        },
        chars = /[aceinosuy]/g;

    return function makeComp(input) {
        return input.replace(chars, function(c){
            return '[' + c + accents[c] + ']';
        });
    };

}());
Run Code Online (Sandbox Code Playgroud)


Sal*_*èse 5

我搜索并推荐了herostwist答案,但一直在搜索,确实如此,这是JavaScript的核心(string.localeCompare函数)

var a = 'réservé'; // with accents, lowercase
var b = 'RESERVE'; // no accents, uppercase

console.log(a.localeCompare(b));
// expected output: 1
console.log(a.localeCompare(b, 'en', {sensitivity: 'base'}));
// expected output: 0
Run Code Online (Sandbox Code Playgroud)

注意,但是,某些移动浏览器仍然缺少全面支持!

在此之前,请注意所有平台和环境的全面支持。

这就是全部 ?

不,我们现在可以继续使用string.toLocaleLowerCase函数。

var dotted = '?stanbul';

console.log('EN-US: ' + dotted.toLocaleLowerCase('en-US'));
// expected output: "istanbul"

console.log('TR: ' + dotted.toLocaleLowerCase('tr'));
// expected output: "istanbul"
Run Code Online (Sandbox Code Playgroud)

谢谢 !

  • "àéçî".toLocaleLowerCase('en-US') 将返回“àéçî”,因此非常有限 (2认同)

use*_*780 5

我认为这是最巧妙的解决方案

\n\n
var nIC = new Intl.Collator(undefined , {sensitivity: 'base'})\nvar cmp = nIC.compare.bind(nIC)\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果两个字符串相同,则返回 0,忽略重音符号。

\n\n

或者你尝试localecompare

\n\n
'\xc3\xaatre'.localeCompare('etre',undefined,{sensitivity: 'base'})\n
Run Code Online (Sandbox Code Playgroud)\n

  • 我的答案是7年前的;这是(大部分)在 2020 年执行此操作的正确方法。我不认为(根据 MDN 的示例)您需要绑定比较方法 - 它应该使用所需的上下文创建,因为 `myNames.sort( nIC.compare)` 工作得很好。 (2认同)