0

这是我要解决的问题:用户可以为网站上的某些内容显示自定义的 4 字符标题,例如NEWS. 我想添加对用户可以从Font Awesome指定图标的方式的支持。

我正在考虑使用方括号,例如,用户会写[camera]pic,这将被翻译为<i class="icon-camera"></i>pic使用正确的 Font Awesome 图标显示。但是,我也希望能够转义标记,以便 (eg)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].

这是我的测试用例。假设将占位符替换为以 a 为前缀的占位符文本的简单转换$,则:

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]

4

3 回答 3

3

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>"
于 2013-03-17T20:55:38.220 回答
2

只是为了演示,这里有一个更优雅的 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
});
于 2013-03-17T20:55:02.110 回答
2

红宝石的解决方案

[word]您可以使用look-behind来防止子字符串[[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);

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

于 2013-03-16T07:30:28.883 回答