处理Javascript RegEx子匹配

时间:2008-09-17 08:00:11

标签: javascript regex markdown

我正在尝试编写一些JavaScript RegEx来用真正的html标记替换用户输入的标签,因此[b]将变为<b>等等。我正在使用的RegEx看起来像这样

var exptags = /\[(b|u|i|s|center|code){1}]((.){1,}?)\[\/(\1){1}]/ig;

使用以下JavaScript

s.replace(exptags,"<$1>$2</$1>");

这适用于单个嵌套标签,例如:

[b]hello[/b] [u]world[/u]

但如果标签彼此嵌套,则它只匹配外部标签,例如

[b]foo [u]to the[/u] bar[/b]

这只会匹配b代码。我怎样才能解决这个问题?我应该循环直到起始字符串与结果相同?我觉得((.){1,}?)模式也错了吗?

由于

8 个答案:

答案 0 :(得分:3)

最简单的解决方案是更换所有标签,无论它们是否已关闭,如果它们相匹配,让.innerHTML解决,否则它会更有弹性......

var tagreg = /\[(\/?)(b|u|i|s|center|code)]/ig
div.innerHTML="[b][i]helloworld[/b]".replace(tagreg, "<$1$2>") //no closing i
//div.inerHTML=="<b><i>helloworld</i></b>"

答案 1 :(得分:1)

AFAIK你不能用正则表达式来表达递归。

然而,你可以使用.NET的System.Text.RegularExpressions使用平衡匹配来做到这一点。点击此处:http://blogs.msdn.com/bclteam/archive/2005/03/15/396452.aspx

如果您使用的是.NET,则可以通过回调实现所需的功能。 如果没有,您可能需要滚动自己的小javascript解析器。

然后,再次,如果您能够负担得起服务器,您可以使用完整的解析器。 :)

无论如何,你需要什么?如果它是预览以外的任何其他内容,我强烈建议您在处理服务器端。

答案 2 :(得分:0)

是的,你必须循环。另外,由于您的代码看起来非常像HTML,因此您可以分别替换[b]的{​​{1}}和<b>的{​​{1}}。 (。){1,}?与(。*?)相同 - 即任何符号,最小可能的序列长度。

更新:感谢MrP,(。){1,}?是(。)+ ?,我的坏。

答案 3 :(得分:0)

你认为内心模式很麻烦。

((.){1,}?)

这是至少进行一次捕获的匹配,然后捕获整个事物。标记中的每个字符都将作为一个组捕获。

您也在不需要时捕获结束元素名称,并在隐含时使用{1}。以下是清理版本:

/\[(b|u|i|s|center|code)](.+?)\[\/\1]/ig

不确定其他问题。

答案 4 :(得分:0)

您可以重复应用正则表达式,直到它不再匹配为止。这会做一些奇怪的事情,比如“[b] [b] foo [/ b] [/ b]”=&gt; “&lt; b&gt; [b] foo&lt; / b&gt; [/ b]”=&gt; “&lt; b&gt;&lt; b&gt; foo&lt; / b&gt;&lt; / b&gt;”,但据我所知,最终结果仍然是一个合理的字符串,其中包含匹配(但不一定是嵌套的)标记。

或者如果你想'正确',只需编写一个简单的递归下降解析器。虽然人们可能期望“[b] foo [u] bar [/ b] baz [/ u]”能够工作,但是用解析器识别它是很棘手的。

答案 5 :(得分:0)

嵌套块未被替换的原因是因为[b]的匹配将位置放在[/ b]之后。因此,((。){1,}?)匹配的所有内容都将被忽略。

可以在服务器端编写递归解析器 - Perl使用qr//而Ruby可能有类似的东西。

虽然,你不一定需要真正的递归。您可以使用相对简单的循环来等效地处理字符串:

var s = '[b]hello[/b] [u]world[/u] [b]foo [u]to the[/u] bar[/b]';
var exptags = /\[(b|u|i|s|center|code){1}]((.){1,}?)\[\/(\1){1}]/ig;

while (s.match(exptags)) {
   s = s.replace(exptags, "<$1>$2</$1>");
}

document.writeln('<div>' + s + '</div>'); // after

在这种情况下,它将进行2次传递:

0: [b]hello[/b] [u]world[/u] [b]foo [u]to the[/u] bar[/b]
1: <b>hello</b> <u>world</u> <b>foo [u]to the[/u] bar</b>
2: <b>hello</b> <u>world</u> <b>foo <u>to the</u> bar</b>

此外,还有一些清理RegEx的建议:

var exptags = /\[(b|u|i|s|center|code)\](.+?)\[\/(\1)\]/ig;
    当没有其他计数说明符存在时,假设
  • {1}
  • {1,}可以缩短为+

答案 6 :(得分:0)

同意Richard Szalay,但他的正则表达没有被引用正确:

var exptags = /\[(b|u|i|s|center|code)](.*)\[\/\1]/ig;

更清洁。请注意,我还将.+?更改为.*.+?有两个问题:

  1. 你不会匹配[u] [/ u],因为它们之间至少没有一个字符(+)
  2. 非贪婪的匹配不会与嵌套在其中的相同标签很好地处理(?)

答案 7 :(得分:0)

怎么样:

tagreg=/\[(.?)?(b|u|i|s|center|code)\]/gi;
"[b][i]helloworld[/i][/b]".replace(tagreg, "<$1$2>");
"[b]helloworld[/b]".replace(tagreg, "<$1$2>");

对我而言,以上产生:

<b><i>helloworld</i></b>
<b>helloworld</b>

这似乎可以满足您的需求,并且只需要一次通过。

免责声明:我不经常在JS中编码,所以如果我犯了任何错误,请随时指出: - )