我正在构建搜索,我将使用javascript自动完成功能。我来自芬兰(芬兰语)所以我必须处理一些特殊的角色,如ä,ö和å
当用户在搜索输入字段中键入文本时,我会尝试将文本与数据匹配。
如果用户输入例如“ää”,这是一个不能正常工作的简单示例。 “äl”
也是如此var title = "this is simple string with finnish word tämä on ääkköstesti älkää ihmetelkö";
// Does not work
var searchterm = "äl";
// does not work
//var searchterm = "ää";
// Works
//var searchterm = "wi";
if ( new RegExp("\\b"+searchterm, "gi").test(title) ) {
$("#result").html("Match: ("+searchterm+"): "+title);
} else {
$("#result").html("nothing found with term: "+searchterm);
}
那么如何让这些ä,ö和å字符与javascript正则表达式一起使用?
我想我应该使用unicode代码但是我应该怎么做?这些字符的代码是: [\ u00C4,\ u00E4,\ u00C5,\ u00E5,\ u00D6,\ u00F6]
=> äÄåÅöÖ
答案 0 :(得分:38)
Regex似乎存在问题,并且字符\b
与字符串的开头匹配,其起始字符超出正常的256字节范围。
请尝试使用\b
(?:^|\\s)
var title = "this is simple string with finnish word tämä on ääkköstesti älkää ihmetelkö";
// Does not work
var searchterm = "äl";
// does not work
//var searchterm = "ää";
// Works
//var searchterm = "wi";
if ( new RegExp("(?:^|\\s)"+searchterm, "gi").test(title) ) {
$("#result").html("Match: ("+searchterm+"): "+title);
} else {
$("#result").html("nothing found with term: "+searchterm);
}
故障:
(?:
括号()
在Regex中形成一个捕获组。括号以问号开头,冒号?:
构成非捕获组。他们只是将这些术语组合在一起
^
插入符号匹配字符串的开头
|
栏是“或”运算符。
\s
匹配空格(在字符串中显示为\\s
,因为我们必须转义反斜杠)
)
关闭群组
因此,我们不使用匹配单词边界且不适用于unicode字符的\b
,而是使用与字符串OR空格的开头匹配的非捕获组。
答案 1 :(得分:16)
JavaScript RegEx中的\b
字符类实际上只对简单的ASCII编码有用。 \b
是\w
和\W
集或\w
之间的边界以及字符串的开头或结尾的快捷代码。这些字符集仅考虑ASCII“单词”字符,其中\w
等于[a-zA-Z0-9_]
而\W
是该类的否定。
这使得RegEx角色类在处理任何真实语言方面基本无用。
\s
应该适用于您想要做的事情,前提是搜索字词仅由空格分隔。
答案 2 :(得分:10)
这个问题很老,但我认为我找到了一个更好的解决方案,用于使用unicode字母的正则表达式中的边界。 使用XRegExp,您可以实现扩展此
的有效\ b边界XRegExp('(?=^|$|[^\\p{L}])')
结果是长达4000多个字符,但它看起来效果很好。
一些解释:(?=)是一个零长度前瞻,它查找开始或结束边界或非字母unicode字符。最重要的想法是前瞻,因为\ b不能捕获任何东西:它只是真或假。
答案 3 :(得分:6)
当你必须使用Unicode中的一组特定字符时,我建议你使用XRegExp,这个库的作者映射了所有类型的区域字符集,使得使用不同语言的工作更容易。< / p>
答案 4 :(得分:2)
使用Unicode时,我发现\b
有些奇怪:
/\bo/.test("pop"); // false (obviously)
/\bä/.test("päp"); // true (what..?)
/\Bo/.test("pop"); // true
/\Bä/.test("päp"); // false (what..?)
似乎\b
和\B
的含义相反,但仅在与非ASCII Unicode一起使用时才有效?可能会有更深层次的事情发生,但我不确定它是什么。
在任何情况下,似乎单词边界都是问题,而不是Unicode字符本身。也许您应该将\b
替换为(^|[\s\\/-_&])
,因为这似乎可以正常工作。 (但是,使你的符号列表比我的更全面。)
答案 5 :(得分:1)
\b
是字母和非字母字符之间转换的快捷方式,反之亦然。
更新和完善max_masseti的答案:
通过在ES2018中为RegExs引入/u
修饰符,您现在可以使用\p{L}
表示任何unicode字母和\P{L}
(注意大写的P
)代表任何东西。
EDIT :先前版本不完整。
因此:
const text = 'A Fé, o Império, e as terras viciosas';
text.split(/(?<=\p{L})(?=\P{L})|(?<=\P{L})(?=\p{L})/);
// ['A', ' Fé', ',', ' o', ' Império', ',', ' e', ' as', ' terras', ' viciosas']
我们使用后退(?<=...)
查找字母,并使用前瞻(?=...)
查找非字母,反之亦然。
答案 6 :(得分:1)
尽管该问题似乎已经存在了8年,但不久前我遇到了一个类似的问题(我必须匹配西里尔字母)。我花了一整天的时间,在StackOverflow上找不到任何合适的答案。因此,为了避免其他人付出很大的努力,我想分享一下我的解决方案。
是的,\b
单词边界仅适用于拉丁字母(Word boundary: \b):
单词边界\ b不适用于非拉丁字母 单词边界测试\ b检查位置的一侧应有\ w,另一侧应是“ not \ w”。 但是\ w表示拉丁字母a-z(或数字或下划线),因此该测试不适用于其他字符,例如西里尔字母或象形文字。
是的,JavaScript RegExp
实现几乎不支持UTF-8编码。
因此,我尝试在非拉丁字符的支持下实现自己的单词边界功能。为了使单词边界仅适用于西里尔字母,我创建了以下正则表达式:
new RegExp(`(?<![\u0400-\u04ff])${cyrillicSearchValue}(?![\u0400-\u04ff])`,'gi')
\u0400-\u04ff
是table of codes中提供的一系列西里尔字符。这不是理想的解决方案,但是,在大多数情况下都可以正常工作。
要使其适合您的情况,您只需要从list of Unicode characters中选取适当范围的代码即可。
要试用我的示例,请运行以下代码段。
function getMatchExpression(cyrillicSearchValue) {
return new RegExp(
`(?<![\u0400-\u04ff])${cyrillicSearchValue}(?![\u0400-\u04ff])`,
'gi',
);
}
const sentence = 'Будь-який текст кирилицею, де необхідно знайти слово з контексту';
console.log(sentence.match(getMatchExpression('текст')));
// expected output: ["текст"]
console.log(sentence.match(getMatchExpression('но')));
// expected output: null
答案 7 :(得分:0)
我的想法是使用代表芬兰字母的代码进行搜索
new RegExp("\\b"+asciiOnly(searchterm), "gi").test(asciiOnly(title))
我最初的想法是使用普通encodeURI
,但%符号似乎会干扰正则表达式。
我使用encodeURI编写了一个粗略的函数来编码代码超过128的每个字符,但删除了它的%并添加了QQ&#39;在一开始的时候。它不是最好的标记,但我无法使用非字母数字。
答案 8 :(得分:0)
我遇到了类似的问题,但我不得不更换一系列术语。如果两个术语在文本中彼此相邻(因为它们的边界重叠),我发现的所有解决方案都没有用。所以我不得不使用一些改进的方法:
var text = "Ještě. že; \"už\" à. Fürs, 'anlässlich' že že že.";
var terms = ["à","anlässlich","Fürs","už","Ještě", "že"];
var replaced = [];
var order = 0;
for (i = 0; i < terms.length; i++) {
terms[i] = "(^\|[ \n\r\t.,;'\"\+!?-])(" + terms[i] + ")([ \n\r\t.,;'\"\+!?-]+\|$)";
}
var re = new RegExp(terms.join("|"), "");
while (true) {
var replacedString = "";
text = text.replace(re, function replacer(match){
var beginning = match.match("^[ \n\r\t.,;'\"\+!?-]+");
if (beginning == null) beginning = "";
var ending = match.match("[ \n\r\t.,;'\"\+!?-]+$");
if (ending == null) ending = "";
replacedString = match.replace(beginning,"");
replacedString = replacedString.replace(ending,"");
replaced.push(replacedString);
return beginning+"{{"+order+"}}"+ending;
});
if (replacedString == "") break;
order += 1;
}
查看小提琴中的代码:http://jsfiddle.net/antoninslejska/bvbLpdos/1/
正则表达式的灵感来自:http://breakthebit.org/post/3446894238/word-boundaries-in-javascripts-regular
我无法说,我发现解决方案很优雅......
答案 9 :(得分:0)
您正在寻找的是Unicode字边界标准:
http://unicode.org/reports/tr29/tr29-9.html#Word_Boundaries
这里有一个JavaScript实现(unciodejs.wordbreak.js)
答案 10 :(得分:0)
问题的正确答案由 andrefs 给出。 将所有必需的内容放在一起后,我只会更清楚地重写它。
对于ASCII文本,可以使用\b
在模式的开头和结尾都匹配单词边界。使用Unicode文本时,您需要使用2种不同的模式来进行相同的操作:
(?<=^|\P{L})
来匹配主要模式之前的开头或单词边界。(?=\P{L}|$)
匹配主模式的结尾或单词边界。(?i)
,以使所有匹配项均不区分大小写。因此,得出的答案是:(?i)(?<=^|\P{L})xxx(?=\P{L}|$)
,其中xxx是您的主要模式。这相当于ASCII文本的(?i)\bxxx\b
。
为使代码正常工作,您现在需要执行以下操作:
'\'
替换为'\\'
,并对正则表达式的任何保留特殊字符(例如'\^', '\$', '\/'
等)执行相同的操作。检查here的相关问题这个。string.replace()
方法,即可将变量的内容插入上面的模式中的“ xxx”位置。