什么是最终用户可编辑的文本替换占位符的简单解决方案?



这是我想解决的问题:用户可以在网站上显示自定义的4个字符的标题,例如NEWS。我想添加一种方式,用户可以从字体Awesome指定图标的支持。

我正在考虑使用括号,例如,用户会写[camera]pic,这将被翻译成<i class="icon-camera"></i>pic,以适当的字体Awesome图标显示。然而,我也希望能够转义标记,以便(例如)f[[x]将被打印为f[x],而不是f[<i class="icon-x"></i>。文本占位符永远不会嵌套,但它们可能是相邻的(例如[star][star][star][star])。我努力使用正则表达式*来解决这个问题,并得出结论,正则表达式可能不是解决这个问题的合适方法。

是否有一个简单的解决方案来解决这种问题,可以在Javascript和Ruby中干净地实现?或者,是否有另一种简单的方法来表示这些类型的文本占位符,以满足我的顺序和可逃避的要求(例如${camera}pic代替)?或者我必须手工解析它,一次解析一个字符?


*至于我尝试过的正则表达式:[(w+)]很简单,但在f[[x]上不应该匹配。(A|[^[])[(w+)]通过了f[[x],但[x][y][z]中的其他占位符都失败了。

以下是我的测试用例。假设一个简单的转换,将占位符替换为前缀为$的占位符文本,则:
describe '#to_var' do
   it { helper.to_var('abcd').should == 'abcd' }
   it { helper.to_var('[foo][bar][baz]').should == '$foo$bar$baz' }
   it { helper.to_var('[[x]').should == '[x]' }
   it { helper.to_var('<[[x]>').should == '<[x]>' }
   it { helper.to_var('<[x]>').should == '<$x>' }   
end

我想到的最接近的正则表达式是:

 icon_code_regex =  %r(
    (A # beginning of string
     | # or
     [^[]) # not a left bracket
    [ # literal left bracket
    (w+) # the good stuff
    ] # literal right bracket
  )x
str.gsub(icon_code_regex, '1$2').gsub('[[', '[')

不符合[foo][bar][baz]的情况

Javascript解决方案:

var str = 'abcd [foo][bar][baz] [[x] <[[x]> <[x]>';
str = str.replace( /([)?[(w+)]/g, function ( match, escaped, icon ) {
    return escaped ? '[' + icon + ']' : '$' + icon;
});
// "abcd $foo$bar$baz [x] <[x]> <$x>"

只是为了演示,这里有一个更优雅的JS解决方案,它使用replace:

var output = str.replace(/[(w+)]/g, function(match, icon, offset) {
    if (offset>0 && str.charAt(offset-1) == '[') // if previous existed and was [
        return match.slice(1); // return the match but without opening [
    // else
    return '<i class="icon-' + icon + '" />'; // or whatever you want to do
});

Ruby的解决方案

您可以使用向后查找来防止[[word]中的子字符串[word]匹配:

(?<![)[(w+)]

查看(?<![)只是检查[是否出现在我们想要匹配的字符串之前。

JS解决方案

对于JS的变通,因为它没有向后看:

// Match one non-opening-bracket character, then the [word],
// but the closing bracket is not consumed, for the case
// of consecutive [word1][word2]
var regex = /(^|[^[])[(w+)(?=])/g;
var arr;
var output = "";
var lastAppend = 0;
while ((arr = regex.exec(inputString)) !== null) {
    // Append substring from index of lastAppend to right before opening [
    // lastAppend will either be at beginning of the string (0)
    // OR right after closing ] from previous match
    output += inputString.substring(lastAppend, arr.index + arr[1].length);
    output += "$" + arr[2];
    // Need to offset by 1 to skip the closing ] (not consumed)
    lastAppend = regex.lastIndex + 1;
}
output += inputString.substring(lastAppend);

它很丑。我不确定是否有更优雅的方式

最新更新