How can I make this regex ignore braces not preceded by a \
var r = new Regex(@"PW\[(?<name>.*)\]");
This regex is supposed to match a name contained between a [
and a ]
. But how do I make the regex ignore braces that are prefixed by a开发者_C百科 \
? I lack the terminology to even google for this.
That is, I need it to find [inuyasha]
with name equal to 'inuyasha', and match [inuyasha\]]
with name = inuyasha\]
.
Make sense?
Correction
The last match should be inuyasha]
. The extra \
was a typo.
The terminology you seek is "negative lookbehind." Note that this feature is not supported by every regex flavor. It exists in Perl and Java, at least.
You can't make a regex ignore anything--not the way you're talking about. What you're describing is a three-step process. First you find a name by locating the enclosing square brackets, while allowing for escaped brackets in the name:
@"\[(?<name>(?:[^\\\[\]]|\\.)*)\]"
The first part of the alternation, [^\\\[\]]
, is a negated character class that matches any one character except a backslash or a square bracket. The second part, \\.
, matches a backslash followed by any one character. It doesn't matter what the second character is; all we need to know is that it's escaped by the backslash.
The second step is to extract the name by means of the capturing group:
string rawName = m.Groups["name"].Value;
...and the third step is to remove any escaping backslashes:
string name = Regex.Replace(rawName, @"\\(.)", "$1");
Putting that all together, we have
string test = @"find [inuyasha] or [\[inuyasha] or [inuyasha\]] or [inu\\yasha].";
Regex reg = new Regex(@"\[(?<name>(?:[^][\\]|\\.)*)\]");
foreach (Match m in reg.Matches(test))
{
string rawName = m.Groups["name"].Value;
string name = Regex.Replace(rawName, @"\\(.)", "$1");
Console.WriteLine(name);
}
output:
inuyasha
[inuyasha
inuyasha]
inu\yasha
Notice the shortened character class in the main regex: [^][\\]
. If the first character in the class (or the first character after the negating ^
) is a right square bracket (]
), it's treated as a literal character, not as the end of the character class. The left square bracket ([
) is always treated as a literal character unless it's used in a set subtraction expression (e.g. [a-z-[aeiou]]
, for a lowercase consonant). This information is specific to the .NET regex flavor; other flavors have their own rules.
If you know there may only be one such \]
before the real end-bracket, you could use a Regex like this:
PW\[(?<name>.*?(\\\])?)\]
If there might be more, you would change the zero-or-one to zero-or-more:
PW\[(?<name>.*?(\\\])*)\]
For a string like "one [two\]] three [four\]\]] five
", the latter would produce these matches:
two\]
four\]\]
Then it would be an easy matter of `Replace("\]", "]") to remove the escaping.
It tried using lookbehind, but could not get it to drop the \
. If you are only matching the ]
, as in a pattern like (?<=\\)\]
, great. As soon as you want to also capture characters before the lookbehind, the characters matched by the lookbehind will also be part of the results. Regex doesn't drop things from the middle of a capture group. You either have to process a capture in a second step, or capture multiple adjacent groups and concatenate the groups you actually want.
精彩评论