使用 JavaScript 执行带/不带重音字符的文本匹配
Posted
技术标签:
【中文标题】使用 JavaScript 执行带/不带重音字符的文本匹配【英文标题】:Using JavaScript to perform text matches with/without accented characters 【发布时间】:2011-08-07 17:20:51 【问题描述】:我正在使用基于 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;
除了这样的替换函数,还有更好的方法吗?也许是为了“deaccent”被比较的字符串?
【问题讨论】:
感谢您的代码,我使用您的函数替换了输入文本中的重音元音并且工作正常。 【参考方案1】:有一种方法可以““去除”被比较的字符串”,而无需使用列出所有要删除的重音符号的替换函数……
这是easiest solution,我可以考虑从字符串中删除重音符号(和其他变音符号)。
查看实际操作:
var string = "Ça été Mičić. ÀÉÏÓÛ";
console.log(string);
var string_norm = string.normalize('NFD').replace(/[\u0300-\u036f]/g, "");
console.log(string_norm);
【讨论】:
这无疑是一种很好的现代方式。请记住,对此不支持 IE 或 Safari 【参考方案2】:遇到这个旧线程,我想我会尝试做一个快速的功能。当它们在函数 replace() 调用时匹配时,我依赖于管道分隔的 OR 设置变量的顺序。我的目标是尽可能多地使用标准的正则表达式实现 javascript 的 replace() 函数,以便可以在低级浏览器优化空间中进行繁重的处理,而不是在昂贵的 javascript 逐字符比较中进行.
这根本不科学,但是当我将此线程中的其他功能插入我的自动完成功能时,我的旧华为 IDEOS android 手机反应迟缓,而此功能会快速运行:
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';
);
如果您是 jQuery 开发人员,这里有一个使用此函数的方便示例;您可以像在选择器中使用 :contains 一样使用 :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;
;
【讨论】:
【参考方案3】:我搜索并支持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
但是请注意,仍然缺少对某些移动浏览器的完全支持!!!
在此之前,请继续关注所有平台和环境的全面支持。
就这些了吗?
不,我们现在可以更进一步,使用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"
谢谢!
【讨论】:
"àéçî".toLocaleLowerCase('en-US') 将返回“àéçî”,因此非常有限【参考方案4】:没有我能想到的“去口音”更简单的方法,但您的替换可以简化一点:
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] + ']';
);
;
());
【讨论】:
【参考方案5】:我认为这是最巧妙的解决方案
var nIC = new Intl.Collator(undefined , sensitivity: 'base')
var cmp = nIC.compare.bind(nIC)
如果两个字符串相同,则返回 0,忽略重音符号。
或者你试试localecompare
'être'.localeCompare('etre',undefined,sensitivity: 'base')
【讨论】:
我的答案是 7 岁;这(大部分)是 2020 年的正确方法。我不相信(通过 MDN 的示例)您需要绑定 compare 方法——它应该使用所需的上下文创建,因为myNames.sort(nIC.compare)
工作正常很好。【参考方案6】:
我做了一个原型版本:
String.prototype.strip = function()
var translate_re = /[öäüÖÄÜß ]/g;
var translate =
"ä":"a", "ö":"o", "ü":"u",
"Ä":"A", "Ö":"O", "Ü":"U",
" ":"_", "ß":"ss" // probably more to come
;
return (this.replace(translate_re, function(match)
return translate[match];)
);
;
像这样使用:
var teststring = 'ä ö ü Ä Ö Ü ß';
teststring.strip();
这会将字符串更改为 a_o_u_A_O_U_ss
【讨论】:
【参考方案7】:首先,我建议使用 switch 语句而不是一长串 if-else if ...
那么,我不确定您为什么不喜欢您当前的解决方案。它当然是最干净的。不考虑“所有字符”是什么意思?
除了使用第三方库之外,JavaScript 中没有标准方法可以将重音字母映射到 ASCII 字母,因此您编写的库与其他库一样好。
另外,“ß”我相信映射到“ss”,而不是单个“s”。请注意土耳其语中带点和不带点的“i”——我相信它们指的是不同的字母。
【讨论】:
我更喜欢haystack.indexOfIgnoreAccents (needle)
选项 :) 我不喜欢做繁重的工作......【参考方案8】:
您也可以使用http://fusejs.io,它自称为“轻量级模糊搜索库。 零依赖”,用于模糊搜索。
【讨论】:
以上是关于使用 JavaScript 执行带/不带重音字符的文本匹配的主要内容,如果未能解决你的问题,请参考以下文章