0

私が解決しようとしている問題は次のとおりです。ユーザーは、Web サイトで何かのカスタム 4 文字のタイトルを表示できますNEWSユーザーがFont Awesomeからもアイコンを指定できる方法のサポートを追加したいと考えています。

たとえば、ユーザーが書き込み、それが適切な Font Awesome アイコンで表示される[camera]picように変換されます。<i class="icon-camera"></i>picただし、マークアップをエスケープできるようにしたいので、(たとえば)ではなくf[[x]として出力されます。テキスト プレースホルダーがネストされることはありませんが、隣接している可能性があります (例: )。正規表現*を使用してこれを解決するのに苦労しましたが、正規表現はおそらく問題の適切な解決策ではないという結論に達しました。f[x]f[<i class="icon-x"></i>[star][star][star][star]

Javascript と Ruby できれいに実装できる、この種の問題に対する簡単な解決策はありますか? または、これらの種類のテキスト プレースホルダーを表す別の簡単な方法はあります${camera}picか? それとも、一度に1文字ずつ手で解析する必要がありますか?


* 私が試した正規表現については:\[(\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]これはケースに失敗します。

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

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);

かなり醜いです。もっとエレガントな方法があるかどうかはわかりません。

于 2013-03-16T07:30:28.883 に答える
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 に答える