This seems to be a robust/reliable pattern:
~#[A-Z]+|\[[^#\]]*\(#[A-Z]+\)[^\]]*]~
Pattern Demo
~ #pattern delimiter
#[A-Z]+ #match hash symbol followed by one or more uppercase letters
| #or
\[ #match an opening square bracket
[^#\]]* #match zero or more non-hash/non-closing square bracket characters
\( #match opening parenthesis
#[A-Z]+ #match hash symbol followed by one or more uppercase letters
\) #match closing parenthesis
[^\]]* #match zero or more non-closing square bracket characters
] #match a closing square bracket
~ #pattern delimiter
This pattern is looking for a "hashtag" substring with no [()]
characters in it OR a "hashtag" substring that will be tightly wrapped in ()
then loosely wrapped in []
which may also contain some characters before the (
or after the )
.
This pattern is efficient because it uses greedy quantifiers and it does not employ any capture groups.