I’m trying to find pairs of numbers in parentheses, then parse them. For that reason I constructed a regular expression with capturing groups inside this snippet of code:
Regex rgx = new Regex(@"\(([0-9]*)\, ?([0-9]*)\)");
MatchCollection matches = rgx.Matches(current["EmptyFields"].InnerText);
if (matches.Count > 0) {
foreach (Match match in matches) {
CaptureCollection captures = match.Captures;
emptyFields.Add(new GameBoardCoords(Int32.Parse (captures[0].Value), Int32.Parse (captures[1].Value)));
}
}
The intended result are two capturing groups, each with one member of a pair. For example, for “(0,0)”, there should be two capturing groups with “0” and “0”. This is how it works when I test the expression in the regex explorer.
For some reason instead, this code generates one capturing group with the entire match - “(0,0)” in our example. Is there something I missed here?
In C#, the backslash () character is a special ‘escape’ character used for representing special characters such as newlines (
). In order to represent a backslash, you must use a double backslash (\) instead.
This can be slightly confusing, since the backslash is being used as an escape character in the regex itself - eg. to represent a left paren instead of the beginning of a capture. But the regex won’t even see the backslash in this case because c# is ‘eating’ it beforehand.
Your regex works perfectly - try it out in Regexr
So why does it not work?
Because you’re accessing the wrong groups.
In a regex match, group 0 is always the whole match!
You can see it in Regexr by hovering over the matches and see which group is which part of the match.
Instead you need to access groups 1 and 2 in your code like so:
emptyFields.Add(new GameBoardCoords(Int32.Parse (captures[1].Value), Int32.Parse (captures[2].Value)));
You may want to change your regex to force number input however, or you might run into an empty string. Basically just replace the *
with +
in the pattern like so:
Regex rgx = new Regex(@"\(([0-9]+)\, ?([0-9]+)\)");
Alternatively, either check for string.IsNullOrRmpty
or use int.TryParse
like so:
if (matches.Count > 0)
{
foreach (Match match in matches)
{
CaptureCollection captures = match.Captures;
// either check for empty strings and fill with default value
int coord1 = string.IsNullOrEmpty(captures[1].Value) ? 0 : Int32.Parse(captures[1].Value);
int coord2 = string.IsNullOrEmpty(captures[2].Value) ? 0 : Int32.Parse(captures[2].Value);
// or use try parse
if (!Int32.TryParse(captures[1].Value, out coord1)) coord1 = 0;
if (!Int32.TryParse(captures[2].Value, out coord2)) coord2 = 0;
emptyFields.Add(new GameBoardCoords(coord1, coord2));
}
}