1

我正在尝试编写一些 JavaScript 正则表达式来用真正的 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,}?)模式不对?

谢谢

4

8 回答 8

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>"
于 2008-09-17T13:51:36.877 回答
1

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

但是,您可以使用 .NET 的 System.Text.RegularExpressions 使用平衡匹配来做到这一点。在此处查看更多信息:http: //blogs.msdn.com/bclteam/archive/2005/03/15/396452.aspx

如果您使用的是 .NET,您可能可以通过回调来实现您所需要的。如果没有,您可能不得不推出自己的小型 javascript 解析器。

再说一次,如果你有能力访问服务器,你可以使用完整的解析器。:)

无论如何,你需要这个做什么?如果它不是用于预览,我强烈建议在服务器端进行处理。

于 2008-09-17T08:18:53.993 回答
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 编码,所以如果我犯了任何错误,请随时指出:-)

于 2008-09-17T13:11:35.383 回答
0

是的,你将不得不循环。或者,由于您的标签看起来很像 HTML 的标签,您可以分别替换[b]for<b>[/b]for </b>。(.){1,}?与 (.*?) 相同 - 即任何符号,最小可能的序列长度。

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

于 2008-09-17T08:27:24.770 回答
0

关于内部模式很麻烦,您是对的。

((.){1,}?)

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

您还可以在不需要时捕获关闭元素名称,并{1}在暗示时使用它。下面是一个清理版本:

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

不确定其他问题。

于 2008-09-17T08:31:21.203 回答
0

您可以重复应用正则表达式,直到它不再匹配。那会做一些奇怪的事情,比如 "[b][b]foo[/b][/b]" => "<b>[b]foo</b>[/b]" => "<b><b >foo</b></b>”,但据我所见,最终结果仍然是带有匹配(尽管不一定正确嵌套)标签的合理字符串。

或者,如果您想“正确”地做到这一点,只需编写一个简单的递归下降解析器。尽管人们可能期望 "[b]foo[u]bar[/b]baz[/u]" 能够工作,但使用解析器很难识别。

于 2008-09-17T09:16:33.793 回答
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,} 可以缩短为 +
于 2008-09-17T09:19:57.217 回答
0

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

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

更干净。请注意,我也更改.+?.*. 有两个问题.+?

  1. 你不会匹配 [u][/u],因为它们之间至少没有一个字符 (+)
  2. 非贪婪匹配不会很好地处理嵌套在自身内部的相同标签(?)
于 2008-09-17T09:51:31.433 回答