Reputation: 57
I'm working on a way to filter and replace broken curly brace tags such as {{hello}
. I've tried out a few regular expressions from here in Stack and tried on my own. The closes I've come is using this regex
(?=(\}(?!\})))((?<!\})\})
which selects the last tag in the example code block below. However it does not select the entire tag, it just selects the ending curly brace }
.
{{hello}}
{{world}}}
{{foobar}}
{{hello}
What I need to do is select any tag that is missing the second ending curly brace like {{hello}
. Can anyone help me with the regex to select this type of tag?
Upvotes: 1
Views: 2446
Reputation: 626806
I suggest using the following expression:
/(?<!{){{[^{}]+}(?!})/
See the regex101 demo
The pattern will match any string of text that starts with {{
not preceded with {
, followed with any 1+ characters other than {
and }
and then a }
that is not followed with }
. Thus, this pattern matches strings of exactly {{xxx}
structure.
Here is a Ruby demo:
"{{hello}".gsub(/(?<!{){{[^{}]+}(?!})/, "\\0}")
# => {{hello}}
Pattern details:
(?<!{)
- a negative lookbehind failing the match if a {
appears immediately to the left of the current position{{
- literal {{
[^{}]+
- 1+ characters other than {
and }
(to allow empty values, use *
instead of +
)}
- a closing single }
(?!})
- a negative lookahead failing the match if a }
appears right after the previously matched }
.Upvotes: 1
Reputation: 110675
I assume we are given a string containing substrings beginning with "{{", followed by a "tag", which is a string of characters other than "{" and "}", followed by either "}" or "}}". We wish to return the tags that are followed by only one right brace. For example:
str = "Sue said {{hello}}, Bob said {{world}\nTom said {{foobar}}, Lola said {{hello}"
We can use the following regex:
r = /
\{\{ # match {{
([^}]+) # match one or more characters other than } in capture group 1
\} # match }
(?:\z|[^}]) # match end of line or a character other than }
# in a non-capture group
/x # free-spacing regex definition mode
str.scan(r).flatten
#=> ["world", "hello"]
The regex could of course be written in the conventional way:
r = /\{\{([^}]+)\}(?:\z|[^}])/
Note
str.scan(r)
=> [["world"], ["hello"]]
hence the need for flatten
.
See String#scan for an explanation.
Obviously, the same regex works if
str = "{{hello}}\n{{world}\n{{foobar}}\n{{hello}"
str.scan(r).flatten
#> ["world", "hello"]
If
words = %w| {{hello}} {{world} {{foobar}} {{hello} |
#=> ["{{hello}}", "{{world}", "{{foobar}}", "{{hello}"]
then
words.select { |w| w =~ r }.map { |w| w[/[^{}]+/] }
=> ["world", "hello"]
Upvotes: 1
Reputation: 6173
filter and replace broken curly brace tags
This problem is really easy to solve if you're not nesting things.
Try this:
[\{]+([^}]+)[}]+
Essentially, you can just replace the match with {{\1}}
(or {{$1}}
, I forget which one Ruby uses.)
It will work as long as there are one or more of {
and }
consecutively around the match.
Upvotes: 1