- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我的目标是通过将阴性名词(德语)包装成 <span>
来突出显示它们带有特定 class="..."
的标签风格。
由于我正在处理非 ASCII 集,我(不幸的是)不能使用“单词边界”\b
在 JavaScript 的 RegEx 中,所以我不得不通过明确列出我认为是单词边界的内容来即兴发挥。
我的代码(经过简化和精简)如下所示:
const wordBoundary = "(^|\\s|$|/|\\?|\\.|\\!|\\ )";
"Liebe Grüße".replace(
new RegExp(`${wordBoundary}(Liebe|Grüße)${wordBoundary}`, "g"),
`<span class="nounF">$1$2$3</span>`
);
但是,这只会突出显示第一个单词,而不是第二个单词,产生
<span class="nounF">Liebe </span>Grüße
.
在控制台中调试 I(几乎是偶然的)发现 if 而不是 RegExp
object 我使用正则表达式初始化程序 - 一切都按预期工作,生成
<span class="nounF">Liebe</span> <span class="nounF">Grüße</span>
:
"Liebe Grüße".replace(
/(^|\\s|$|\/|\\?|\\.|\\!|\\ )(Liebe|Grüße)(^|\\s|$|\/|\\?|\\.|\\!|\\ )/g,
`<span class="nounF">$1$2$3</span>`
);
我的问题有两个方面:
RegExp
是不是做错了什么?对象而不使用就地正则表达式初始化程序?因为这对我来说看起来像是一个错误,TBHwordBoundary
为了它?最佳答案
首先让我们考虑一下您的单词边界:
const wordBoundary = "(^|\\s|$|/|\\?|\\.|\\!|\\ )";
与其他地方断言的相反,这是正确转义。它不一定是最好的编写方式,但它会起作用。 |\\)
末尾的空格不是必需的,因为它已经被 \\s
> 覆盖 您也不需要转义 !
,但不会造成伤害。
让我们考虑一个仅使用 ASCII 的类似示例:
const wordBoundary = "(^|\\s|$|/|\\?|\\.|\\!|\\ )";
console.log(
"cat dog".match(new RegExp(`${wordBoundary}(cat|dog)${wordBoundary}`, 'g'))
);
注意它只匹配 cat
而不是 dog
。或者更准确地说,它匹配 'cat '
,末尾有一个空格。这是关键。该空格已被匹配,因此您在尝试匹配 dog
时无法再次匹配它。比赛不能重叠。为避免此问题,您需要使用正向预测来确保空间未被占用:
const wordBoundary = "(^|\\s|$|/|\\?|\\.|\\!|\\ )";
console.log(
"cat dog".match(new RegExp(`${wordBoundary}(cat|dog)(?=${wordBoundary})`, 'g'))
);
更好的是,现在它同时匹配 cat
和 dog
。请注意空格现在位于 'dog'
的开头,因为它是第二个匹配项的一部分,而不是第一个匹配项的一部分。
为了让事情回到你原来的例子,我们可以这样写:
const wordBoundary = '[\\s/?.!]';
var re = new RegExp(`(^|${wordBoundary})(Liebe|Grüße|Ärztin)(?=${wordBoundary}|$)`, 'g');
console.log(re);
// Test cases
[
'Liebe Grüße',
'Liebe asGrüße Liebe Grüße Ärztin Grüße bd',
'Liebe GrüßeLiebe Grüße Ärztin Grüße bd',
'Liebe Grüßeas Liebe Grüße Ärztin Grüße bd',
'Liebe as Grüße Liebe Grüße Ärztin Grüße bd',
'Liebe Ärztin Grüße',
'Liebe\nGrüße',
'Liebe\tGrüße',
'Liebe?Grüße',
'Liebe.Grüße',
'Liebe!Grüße',
'Liebe/Grüße',
'Liebe\\Grüße'
].forEach(function(str) {
console.log(str.replace(re, '$1<b>$2</b>'));
});
虽然我更改了该示例中单词边界的书写方式,但应该注意的是,完全按照问题中的书写方式书写也可以正常工作。
这留下了一个悬而未决的问题:为什么额外的转义看起来有效?这里有一个更简单的例子来帮助证明这一点:
// This is the same as:
// var re = new RegExp('(\\\\?)(Liebe|Grüße)(\\\\?)', 'g');
var re = /(\\?)(Liebe|Grüße)(\\?)/g;
console.log("Liebe Grüße".replace(re, `<b>$1$2$3</b>`));
console.log("LiebeXX Grüße".replace(re, `<b>$1$2$3</b>`));
console.log("Liebe\\Grüße".replace(re, `<b>$1$2$3</b>`));
我去掉了大部分的单词边界,只留下了交替的关键部分,\\?
。双斜杠是单斜杠的转义序列,?
被视为“可选”修饰符。所以这匹配一个可选的 \
。换句话说,单词 boundary 很乐意匹配一个空字符串。实际上,它只是完全忽略单词边界,除非该边界是 \
字符。
当您使用字符串创建 RegExp 时,您需要额外对斜杠进行一次转义(一次用于字符串文字,一次用于 RegExp)。但是,您已经在原始示例中这样做了。通过再次转义它们(这样您就有 4 个斜线),您将以“匹配可选斜线”的情况结束。
关于JavaScript 正则表达式行为不当,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46310247/
我正在编写一个 native iOS 7 应用程序,需要从 JSON api(由我控制)检索数据。 JSON 输出示例如下: { "id" : "544", "name" : "1900 Green
我是一名优秀的程序员,十分优秀!