Javascript RegExp + Word 边界 + unicode 字符

IT技术 javascript regex unicode
2021-01-17 06:29:26

我正在构建搜索,我将使用 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);   
}

http://jsfiddle.net/7TsxB/

那么我怎样才能让那些 ä、ö 和 å 字符与 javascript 正则表达式一起使用呢?

我想我应该使用 unicode 代码,但我应该怎么做?这些字符的代码是:[\u00C4,\u00E4,\u00C5,\u00E5,\u00D6,\u00F6]

=> äÄåÅöÖ

6个回答

正则表达式似乎存在问题,并且单词边界\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形成一个捕获组。括号以问号和冒号开始,?:形成一个非捕获组。他们只是将术语组合在一起

^ 插入符号匹配字符串的开头

| bar 是“或”运算符。

\s匹配空格(出现\\s在字符串中,因为我们必须转义反斜杠)

) 关闭群

因此\b,我们不使用匹配单词边界且不适用于 unicode 字符的 ,而是使用匹配字符串或空格开头的非捕获组。

是否有任何理由不在正则表达式中包含 $(字符串结尾)?即 (?:^|\s|$)
2021-03-14 06:29:26
这也匹配部分字符串匹配。'¿dónde está la alcaldesa?':es并且está匹配,这很糟糕。está应匹配。\\b应该对全字边界有帮助。
2021-03-15 06:29:26
“试试这个”不是解决方案。提供一些关于为什么建议的正则表达式有效的信息。什么是(?:^|\\s)真的?你根本不解释这个解决方案。
2021-03-23 06:29:26
这不是正确的解决方案。(?:^|\\s)不是像 is 那样的零宽度断言\b,并且会消耗匹配中的字符。正向前瞻将是一个更好的主意 ( (?=^|\\s)),但仅在比赛结束后才有效,因为仍然不支持后视。此外,单词边界不仅仅是空格和字符串边界,而是大量其他字符。
2021-03-25 06:29:26
当匹配位于字符串的开头或空格之后时,建议的正则表达式没有相同的行为。当它在开头匹配时返回匹配的文本,但是当它在空格之后匹配时,它也会返回空格作为匹配的一部分,即使捕获是用冒号完成的。测试代码(在 Firefox 控制台中执行): let str1 = "un ejemplo"; 让 str2 = "ejemplo uno"; 让 reg = /(?:^|\s)un/gi; str1.match(reg); // ["un"] str2.match(reg); // [" un"]
2021-04-01 06:29:26

\bJavaScript RegEx 中字符类实际上只对简单的 ASCII 编码有用。 \b是用于设置\w\W设置或\w和字符串开头或结尾之间的边界的快捷代码这些字符集只考虑 ASCII“单词”字符,其中\w等于[a-zA-Z0-9_]并且\W是该类的否定。

这使得 RegEx 字符类在处理任何真实语言时基本上无用。

\s 应该适用于您想要做的事情,前提是搜索词仅由空格分隔。

+1,但\b不是一个字符类速记喜欢\w\s,这是一个零宽度断言像\A$和lookarounds。
2021-03-22 06:29:26

这个问题很老了,但我想我找到了一个更好的解决方案来解决带有 unicode 字母的正则表达式中的边界问题。使用 XRegExp 库,你可以实现一个有效的 \b 边界扩展这个

XRegExp('(?=^|$|[^\\p{L}])')

结果是一个 4000+ 个字符长,但它似乎工作得很好。

一些解释: (?= ) 是一个零长度的前瞻,它寻找开始或结束边界或非字母 unicode 字符。最重要的想法是前瞻,因为 \b 不捕获任何内容:它只是真或假。

当您必须使用来自 Unicode 的特定字符集时,我建议您使用XRegExp,该库的作者映射了所有类型的区域字符集,使使用不同语言的工作更容易。

\b 是字母和非字母字符之间转换的快捷方式,反之亦然。

更新和改进max_masseti的答案:

随着/uES2018 中 RegEx 修饰符的引入,您现在可以\p{L}用来表示任何 unicode 字母,并且\P{L}(注意大写P)表示除此之外的任何内容。

编辑:以前的版本不完整。

像这样:

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']

我们使用lookbehind(?<=...)来查找字母,使用lookahead(?=...)来查找非字母,反之亦然。

我实际上已经尝试过,(?<=^|\P{L})xxx(?=\P{L}|$)实际上它不能正常工作,至少在 JavaScript 中是这样。
2021-03-22 06:29:26
非常酷,我(?<!\\S)$1(?!\\S)用于 unicode 单词匹配。
2021-03-26 06:29:26
请注意,lookbehind 实际上比/u修饰符具有更差的浏览器支持——“每个人”除了 IE 都有/u,但 Safari 和相关浏览器还没有lookbehind。
2021-03-31 06:29:26