6

我正在寻找一种方法来用它们的 HTML 等价物正确替换嵌套的自定义标签。例如,假设我们有以下文本:

This is {b:bold text}

应该变成:

This is <b>bold text</b>

我知道我可以 - 并且可能应该 - 使用带有“粗体”类的跨度之类的东西,而不是旧的“b”标签,但出于本示例的目的,我坚持使用“b”是有原因的. 我可能有嵌套标签:

This is {b:bold text and {i:italic}}

应该变成:

This is <b>bold text and <i>italic</i></b>

但是,我有这些正则表达式(与 replace() 函数一起使用):

/\{b:([\s\S]*?)\}/gm
/\{i:([\s\S]*?)\}/gm

然后结果会变成:

This is <b>bold text and <i>italic</b></i>

标签未正确嵌套。同样,在这种情况下,使用 span 可以解决这个问题,但是对于诸如“ul”、“li”、“h1”之类的东西不起作用……如果文本看起来像这样,贪婪的正则表达式也会导致问题:

This is {b:bold text} and {i:italic}

所以我目前的解决方案是先用 span 替换所有内容,使用 data-tag 属性来指示它实际上应该是什么,然后使用 jQuery 查找所有 span 节点并用适当的标签替换它们:

{h:This is a header}
becomes
<span data-tag='h1'>This is a header</span>
becomes
<h1>This is a header</h1>

它运作良好,但我想知道是否有更简单的方法来做到这一点。中间方法感觉有点像胶带解决方案,我想“美化”它。

有什么建议么?

4

2 回答 2

1

一个简单的堆栈有很长的路要走

function doReplace( str ) {
    var stack = [],
        ret = [],
        ch;
    for( var i = 0, l = str.length; i < l; ++i ) {
        var ch = str.charAt(i);

        if( ch === "{" ) {
            var pos = str.indexOf( ":", i+1);
            if( pos < 0 ) {
                throw new SyntaxError();
            }
            var tagName = str.substring( i + 1, pos);
            if( /[^A-Za-z0-9]/.test(tagName)) {
                throw new SyntaxError();
            }
            ret.push( "<" + tagName + ">" );
            stack.push( tagName);
            i+= tagName.length + 1;
        }
        else if( ch === "}" ) {
            if( !stack.length ) {
                throw new SyntaxError();
            }
            var tagName = stack.pop();
            ret.push( "</" + tagName + ">" );
        }
        else {
            ret.push( ch );
        }
    }

    if( stack.length ) {
        throw new SyntaxError();
    }

    return ret.join("");
}

doReplace( "This is {b:bold text {i:italic text{i:italic text{i:italic text{i:italic text{i:italic text{i:italic text}}}}}}}")
//"This is <b>bold text <i>italic text<i>italic text<i>italic text<i>italic text<i>italic text<i>italic text</i></i></i></i></i></i></b>"
于 2012-12-20T19:26:09.447 回答
0

抛弃正则表达式并使用许多模板工具之一,例如Mustachet.js

编辑: 固定!

...但是,如果您要避免生活中的这种简单性,那么以下是使用正则表达式的方法:

var rex = /\{(b|i):([^{}]*)\}/igm,
    parse = function(txt) {
        var cnt = 0,
            more = true;
        while (more) {
            txt = txt.replace(rex, function(match, $1, $2) {
                return "<" + $1 + ">" + $2 + "</" + $1 + ">";
            });
            more = rex.test(txt);
            cnt++;
        }
        return txt;
    };

因此,您调用parse并将其传递给您的字符串。它递归地解析您的字符串,直到找不到其他标记。这个新的反向工作,解析出其中没有项目的项目,然后向外移动。

要实现您添加的 H1 示例,您可以代替我们{h1:This is the header}并将其添加到子句中,或者在替换函数中(b|i)使用语句而不是仅返回 $1。switch

这是JSFiddle

于 2012-12-20T19:06:40.443 回答