I modified your regex to ignore all hyphens inside braces:
/^-((?:(?:(?!{.*?})[^-\n]|{.*?})|(?:(?:(?!{.*?})[^-\n]|{.*?})*?-){2})*)-/
Demo can be found here. The demo includes \n
in the [^-]
parts, because it takes the whole file as input instead of going line-by-line.
Compared to your original regex, I've replaced both [^-]
parts with this:
(?:(?!{.*?})[^-]|{.*?})
This piece of logic ensures that hyphens between braces are not counted. It has to be included twice to ensure that hyphens between braces are also skipped in 'the even-counter'.
I've used a lookahead conditional to check if there's a matching closing brace, rewriten as described here to support javascript. If a closing brace is found, we match the entire part between the braces unconditionally. If no closing brace can be found, we just treat it as a normal character.
It does not yet support nested braces correctly, but that can be added using a similar construct as you used for hyphens.
Why is the negative lookahead necessary?
The goal is to skip all hyphens between braces. To explain how it works, let's consider the following, much simpler regex: ^-(?:[^-]|{.*?})*-
. This regex tries to find the next hyphen that is not between braces.
The [^-]
part consumes any character that is not a hyphen. The regex executor will walk over the string, character by character, until it encounters a hyphen.
-No match found {here|-}.
It will not use the other option, because the first one suffices.
In this position, the next character is a hyphen. This will match the last hyphen in the regex, finishing the matching proceidure.
-No match found {here-|}.
Unforutnately, this hyphen is between braces and should have been ignored.
One could try to change the order of the options like so: ^-(?:{.*?}|[^-])*-
.
If we try another example, we'll see that it works correctly:
-But this last {hyphen-} works-|
However, when we use the original example, something goes wrong.
The difference occurs in this position:
-No match found |{here-}.
Here, the regex executor first tries to jump over the content between braces, like so:
-No match found {here-}|.
It will then fail to find a hyphen in the rest of the string. But the regex executor isn't stupid. There are two options, so it will just try the second option at the opening brace. This allows the executor to enter the content between the braces, and it will find the hyphen in there:
-No match found {here-|}.
When we add in the negative lookahead, the regex looks like this: ^-(?:(?!{.*?})[^-]|{.*?})*-
. Again, the difference is at this position:
-No match found |{here-}.
Here, the negative lookahead matches. This forces the regex executor to use the other option. Doing so results in the following situation:
-No match found {here-}|.
The regex executor jumped over the entire part between braces, and the negative lookahead ensures that backtracking won't change this. Because the second hyphen is in between the braces and the regex executor won't enter the braces, it can't find the second brace, and will mark this string as 'no match'.