我正在尝试用弯引号替换双引号,除非文本包含在某些标签中,例如 [quote] 和 [code]。
示例输入
[quote="Name"][b]Alice[/b] said, "Hello world!"[/quote]
<p>"Why no goodbye?" replied [b]Bob[/b]. "It's always Hello!"</p>
预期输出
[quote="Name"][b]Alice[/b] said, "Hello world!"[/quote]
<p>“Why no goodbye?” replied [b]Bob[/b]. “It's always Hello!”</p>
我想出了如何通过使用 (*SKIP)(*F)
在 PHP 中优雅地实现我想要的东西,但是我的代码将在 javascript 中运行,而 javascript 解决方案并不理想。
现在我在这些标签处拆分字符串,运行替换,然后将字符串放在一起:
var o = 3;
a = a
.split(/(\[(?<first>(?:icode|quote|code))[^\]]*?\](?:[\s]*?.)*?[\s]*?\[\/(?:\k<first>)\])/i)
.map(function(x,i) {
if (i == o-1 && x) {
x = '';
}
else if (i == o && x)
{
x = x.replace(/(?![^<]*>|[^\[]*\])"([^"]*?)"/gi, '“$1”')
o = o+3;
}
return x;
}).join('');
Javascript 正则表达式分解
- 内部
split()
:-
(\[(?<first>icode|quote|code)[^\]]*?\](?:.)*?\[\/(\k<first>)\])
- 捕获括号内的模式:-
\[(?<first>quote|code|icode)[^\]]*?\]
- 一个[quote]
,[code]
, 或[icode]
打开标签,带或不带参数,如=html
,例如[code=html]
-
(?:[\s]*?.)*?
- 任何字符 (.
) 出现次数超过 0 次(尽可能少),前面有或没有空格,因此如果开始标记后跟换行符,它不会中断 -
[\s]*?
- 0+ 个空格 -
\[\/(\k<first>)\]
-[\quote]
,[\code]
, 或[\icode]
关闭标签。匹配(?<first>)
中捕获的文本团体。例如:如果它是一个 quote 开始标签,它将是一个 quote 结束标签
-
-
- 内部
replace()
:-
(?![^<]*>|[^\[]*\])"([^"]*?)"
- 捕获双引号内的文本:-
(?![^<]*>|[^\[]*\])
- 否定先行,查找字符(不是<
或[
)后跟>
或]
并丢弃它们,因此它不会匹配任何 inside bbcode 和 html 标签。例如:[spoiler="Name"]
或<span style="color: #24c4f9">
.请注意,标签中包装的匹配项保持不变。 -
"
- 文字开头的双引号字符。 -
([^"]*?)
- 任何 0+ 字符,双引号除外。 -
"
- 文字结束双引号字符。
-
-
SPLIT() 正则表达式演示: https://regex101.com/r/Ugy3GG/1
那太糟糕了,因为替换被执行了多次。
与此同时,使用单个 PHP 正则表达式可以获得相同的结果。我写的正则表达式是基于 Match regex pattern that isn't within a bbcode tag .
(\[(?<first>quote|code|icode)[^\]]*?\](?:[\s]*?.)*?[\s]*?\[\/(\k<first>)\])(*SKIP)(*F)|(?![^<]*>|[^\[]*\])"([^"]*?)"
PHP 正则表达式分解
-
(\[(?<first>quote|code|icode)[^\]]*?\](?:[\s]*?.)*?[\s]*?\[\/(\k<first>)\])(*SKIP)(*F)
- 匹配捕获括号内的模式,就像 javascriptsplit()
以上,然后(*SKIP)(*F)
使正则表达式引擎忽略匹配的文本。 -
|
- 或者 -
(?![^<]*>|[^\[]*\])"([^"]*?)"
- 以与 javascriptreplace()
相同的方式捕获双引号内的文本做
PHP 演示: https://regex101.com/r/fB0lyI/1
这个正则表达式的美妙之处在于它只需要运行一次。没有字符串的拆分和连接。有没有办法在 javascript 中实现它?
最佳答案
因为 JS 缺少回溯动词,你将需要使用那些括号中的 block ,但稍后按原样替换它们。通过从您自己的正则表达式中获取交替的第二面,最终的正则表达式将是:
\[(quote|i?code)[^\]]*\][\s\S]*?\[\/\1\]|(?![^<]*>|[^\[]*\])"([^"]*)"
但棘手的部分是使用带有 replace()
方法的回调函数:
str.replace(regex, function($0, $1, $2) {
return $1 ? $0 : '“' + $2 + '”';
})
如果第一个捕获组存在,上面的三元运算符返回 $0
(完整匹配),否则它将第二个捕获组值括在大引号中并返回它。
注意:这可能会在不同情况下失败。
关于javascript - 正则表达式排除包裹在特定 bbcode 标签中的匹配项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54961432/