Here's the problem I'm trying to solve: a user can display a custom 4-character title for something on a web site, e.g. NEWS
. I want to add support for a way that a user can specify icons from Font Awesome as well.
I was thinking about using brackets, e.g. the user would write [camera]pic
and that would be translated to <i class="icon-camera"></i>pic
to be displayed with the proper Font Awesome icon. However, I would also like to be able to escape the markup, so that (e.g.) f[[x]
would be printed as f[x]
, not f[<i class="icon-x"></i>
. The text placeholders will never be nested, but they maybe be adjacent (e.g. [star][star][star][star]
). I struggled to solve this using regular expressions*, and concluded that regular expressions probably aren't the appropriate solution to the problem.
Is there a simple solution to this kind of problem that can be cleanly implemented in Javascript and Ruby? Alternatively, is there another simple way to represent these kinds of text placeholders that meet my sequential and escapable requirements (e.g. ${camera}pic
instead)? Or will I have to parse it by hand, one character at a time?
* As for the regular expressions I've tried: \[(\w+)\]
is simple but matches when it shouldn't on f[[x]
. (\A|[^\[])\[(\w+)\]
is passes f[[x]
but fails for every other placeholder in [x][y][z]
.
Here are my test cases. Assuming a simple transform of replacing the placeholder the placeholder text prefixed with a $
, then:
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
The closest regex I came up with was:
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('[[', '[')
which fails the [foo][bar][baz]
case.