find word only in single braces using regex in python
Question:
I have a string like
text= '{username} joined {servername} {{anytext}} '
and a simple regex code
print(re.findall('{([^{}]*)}', text))
#output
['username', 'servername', 'anytext']
Where anytext
is inside double braces but it is also validating by the regex. I mean, the regex should only find word in single braces and ignore double braces.
Please help me to do this happen.
Answers:
Assuming you only expect either {...}
or {{...}}
we can use the following re.findall
trick:
text = '{username} joined {servername} {{anytext}}'
matches = [x for x in re.findall(r'{{.*?}}|{(.*?)}', text) if x]
print(matches) # ['username', 'servername']
The trick here is to match {{...}}
first in the alternation followed by {...}
, while only capturing the second single bracket version. We filter off the empty matches, leaving behind the matches we want.
You can match the string against the regular expression
(?<!{{)(?<={)[^{}]*?(?=})(?!}})
As seen, there are two matches:
'{username} joined {servername} {{anytext}}'
^^^^^^^^ ^^^^^^^^^^
The expression can be broken down as follows.
(?<!{{) # a negative lookbehind asserts the current location
# in the string is not preceded by '{{'
(?<={) # a positive lookbehind asserts the current location
# in the string is preceded by '{'
[^{}]*? # match zero or more characters other than '{' and '}'
(?=}) # a positive lookahead asserts the current location
# in the string is followed by '}'
(?!}}) # a negative lookahead asserts the current location
# in the string is not followed by '}}'
If desired, the negative lookarounds could be embedded in the positive ones:
(?<=(?<!{{){)[^{}]*?(?=}(?!}))
The string could first be tested to have balanced braces by matching it against the following regular expression.
^[^{}]*(?:(?:{[^{}]*}|{{[^{}]*}})[^{}]*)*$
Hover the cursor over each part of the expression at the link to obtain an explanation of its function.
I have a string like
text= '{username} joined {servername} {{anytext}} '
and a simple regex code
print(re.findall('{([^{}]*)}', text))
#output
['username', 'servername', 'anytext']
Where anytext
is inside double braces but it is also validating by the regex. I mean, the regex should only find word in single braces and ignore double braces.
Please help me to do this happen.
Assuming you only expect either {...}
or {{...}}
we can use the following re.findall
trick:
text = '{username} joined {servername} {{anytext}}'
matches = [x for x in re.findall(r'{{.*?}}|{(.*?)}', text) if x]
print(matches) # ['username', 'servername']
The trick here is to match {{...}}
first in the alternation followed by {...}
, while only capturing the second single bracket version. We filter off the empty matches, leaving behind the matches we want.
You can match the string against the regular expression
(?<!{{)(?<={)[^{}]*?(?=})(?!}})
As seen, there are two matches:
'{username} joined {servername} {{anytext}}'
^^^^^^^^ ^^^^^^^^^^
The expression can be broken down as follows.
(?<!{{) # a negative lookbehind asserts the current location
# in the string is not preceded by '{{'
(?<={) # a positive lookbehind asserts the current location
# in the string is preceded by '{'
[^{}]*? # match zero or more characters other than '{' and '}'
(?=}) # a positive lookahead asserts the current location
# in the string is followed by '}'
(?!}}) # a negative lookahead asserts the current location
# in the string is not followed by '}}'
If desired, the negative lookarounds could be embedded in the positive ones:
(?<=(?<!{{){)[^{}]*?(?=}(?!}))
The string could first be tested to have balanced braces by matching it against the following regular expression.
^[^{}]*(?:(?:{[^{}]*}|{{[^{}]*}})[^{}]*)*$
Hover the cursor over each part of the expression at the link to obtain an explanation of its function.