0

我有这段代码:

var s_1 = 'blabla [size=42]the answer[/size] bla bla blupblub';
var s_2 = 'blabla [size=42]the answer[/size] bla bla blupblub [size=32] 32 [/size]';

alert('Test-String:\n' + s_1 + '\n\nReplaced:\n' + size(s_1));
alert('Test-String:\n' + s_2 + '\n\nReplaced:\n' + size(s_2));


function size(s) {
    var reg = /\[size=(\d{1,2})\]([\u0000-\uFFFF]+)\[\/size\]/gi;
    s = s.replace(reg, function(match, p1, p2) {
        return '<span style="font-size: ' + ((parseInt(p1) > 48) ? '48' : p1) + 'px;">' + p2 + '</span>';
    })
    return s;    
}

它应该替换所有出现的“[size=nn][/size]”标签,但它只替换外部标签。我无法弄清楚如何替换所有这些。(请不要推荐使用 PHP 脚本,我想对 BB-Code 格式的文本进行实时预览)

测试一下

4

4 回答 4

4

匹配(可能是嵌套的)BBCode 标签

如果元素是嵌套的,则需要多通道方法。这可以通过以下两种方式之一来完成;从内向外匹配(不需要递归表达式),或从外向内匹配(需要递归表达式)。(另请参阅我对类似问题的回答:PHP,preg_replace 中的嵌套模板)但是,由于 Javascript 正则表达式引擎不支持递归表达式,因此(正确)使用正则表达式执行此操作的唯一方法是由内而外。下面是一个经过测试的函数,它从内到外用 SPAN html 标签替换 BBCode SIZE 标签。请注意,下面的(快速)正则表达式很复杂(一方面它实现了 Jeffrey Friedl 的“展开循环”效率技术 - 请参阅:掌握正则表达式(第 3 版)有关详细信息),并且 IMO 所有复杂的正则表达式都应进行彻底的注释和格式化以提高可读性。由于 Javascript 没有自由间距模式,因此下面的正则表达式首先在 PHP 自由间距模式下完全注释。实际使用的未注释 js 正则表达式与详细注释的相同。

正则表达式匹配最里面的(可能是嵌套的)大小标签:

// Regular expression in commented (PHP string) format.
$re = '% # Match innermost [size=ddd]...[/size] structure.
    \[size=            # Literal start tag name, =.
    (\d+)\]            # $1: Size number, ending-"]".
    (                  # $2: Element contents.
      # Use Friedls "Unrolling-the-Loop" technique:
      #   Begin: {normal* (special normal*)*} construct.
      [^[]*            # {normal*} Zero or more non-"[".
      (?:              # Begin {(special normal*)*}.
        \[             # {special} Tag open literal char,
        (?!            # but only if NOT start of
          size=\d+\]   # [size=ddd] open tag
        | \/size\]     # or [/size] close tag.
        )              # End negative lookahead.
        [^[]*          # More {normal*}.
      )*               # Finish {(special normal*)*}.
    )                  # $2: Element contents.
    \[\/size\]         # Literal end tag.
    %ix';

Javascript函数:parseSizeBBCode(text)

function parseSizeBBCode(text) {
    // Here is the same regular expression in javascript syntax:
    var re = /\[size=(\d+)\]([^[]*(?:\[(?!size=\d+\]|\/size\])[^[]*)*)\[\/size\]/ig;
    while(text.search(re) !== -1) {
        text = text.replace(re, '<span style="font-size: $1pt">$2</span>');
    }
    return text;
}

示例输入:

r'''
[size=10] size 10 stuff
    [size=20] size 20 stuff
        [size=30] size 30 stuff [/size]
    [/size]
[/size]
'''

示例输出:

r'''
<span style="font-size: 10pt"> size 10 stuff
    <span style="font-size: 20pt"> size 20 stuff
        <span style="font-size: 30pt"> size 30 stuff </span>
    </span>
</span>
'''

免责声明 - 不要使用此解决方案!

请注意,使用正则表达式解析 BBCode 充满危险!(这里没有提到很多“陷阱”。)很多人会说这是不可能的。但是,我强烈反对并且实际上已经编写了一个完整的 BBCode 解析器(在 PHP 中),它使用递归正则表达式并且工作得非常好(而且速度很快)。您可以在这里看到它的实际效果:New 2011 FluxBB Parser(请注意,它使用了一些非常复杂的正则表达式,不适合胆小的人)。

但总的来说,我强烈警告不要使用正则表达式解析 BBCode,除非你对正则表达式有非常深刻和透彻的理解(这可以通过仔细研究和实践Friedl 的杰作来获得)。换句话说,如果您不是 regex 的大师(即 regex guru),请避免将它们用于除最琐碎的应用程序之外的任何应用程序。

于 2012-10-17T16:33:57.667 回答
2
var reg = /\[size=(\d{1,2})\]([\u0000-\uFFFF]+?)\[\/size\]/gi;
                                              ↑
                                    make it lazy (non-greedy)

这与

var reg = /\[size=(\d{1,2})\](.+?)\[\/size\]/gi;
于 2012-10-17T14:35:09.937 回答
1

我会尝试使用([\u0000-\uFFFF]+?) (untested),这告诉在第一次出现时停止,[/size]而不是直接进入最后一次

编辑

是的,经过测试,似乎还可以

于 2012-10-17T14:33:27.020 回答
1

?您需要在 .之后使用非贪婪表达式,由 . 限定+

演示

于 2012-10-17T14:33:52.883 回答