简体   繁体   中英

Why isn't C# following my regex?

I have a C# application that reads a word file and looks for words wrapped in < brackets >

It's currently using the following code and the regex shown.

 private readonly Regex _regex = new Regex("([<])([^>]*)([>])", RegexOptions.Compiled);

I've used several online testing tools / friends to validate that the regex works, and my application proves this (For those playing at home, http://wordfiller.codeplex.com )!

My problem is however the regex will also pickup extra rubbish.

EG

I'm walking on <sunshine>.

will return

sunshine>.

it should just return

<sunshine>

Anyone know why my application refuses to play by the rules?

I don't think the problem is your regex at all. It could be improved somewhat -- you don't need the ([]) around each bracket -- but that shouldn't affect the results. My strong suspicion is that the problem is in your C# implementation, not your regex.

Your regex should split <sunshine> into three separate groups: < , sunshine , and > . Having tested it with the code below, that's exactly what it does. My suspicion is that, somewhere in the C# code, you're appending Group 3 to Group 2 without realizing it. Some quick C# experimentation supports this:

private readonly Regex _regex = new Regex("([<])([^>]*)([>])", RegexOptions.Compiled);
private string sunshine()
{
    string input = "I'm walking on <sunshine>.";
    var match = _regex.Match(input);
    var regex2 = new Regex("<[^>]*>", RegexOptions.Compiled); //A slightly simpler version

    string result = "";

    for (int i = 0; i < match.Groups.Count; i++)
    {
        result += string.Format("Group {0}: {1}\n", i, match.Groups[i].Value);
    }

    result += "\nWhat you're getting: " + match.Groups[2].Value + match.Groups[3].Value;
    result += "\nWhat you want: " + match.Groups[0].Value + " or " + match.Value;        
    result += "\nBut you don't need all those brackets and groups: " + regex2.Match(input).Value;

    return result;
}

Result:

Group 0: <sunshine>
Group 1: <
Group 2: sunshine
Group 3: >

What you're getting: sunshine>
What you want: <sunshine> or <sunshine> 
But you don't need all those brackets and groups: <sunshine> 

We will need to see more code to solve the problem. There is an off by one error somewhere in your code. It is impossible for that regular expression to return sunshine>. . Therefore the regular expression in question is not the problem. I would assume, without more details, that something is getting the index into the string containing your match and it is one character too far into the string.

If all you want is the text between < and > then you'd be better off using:

 [<]([^>]*)[>] or simpler: <([^>]+)>

If you want to include < and > then you could use:

 ([<][^>]*[>]) or simpler: (<[^>]+>)

You're expression currently has 3 Group Matches - indicated by the brackets ().

In the case of < sunshine> this will currently return the following:

Group 1 : "<"

Group 2 : "sunshine"

Group 3 : ">"

So if you only looked at the 2nd group it should work!

The only explanation I can give for your observed behaviour is that where you pull the matches out, you are adding together Groups 2 + 3 and not Group 1.

What you posted works perfectly fine.

        Regex _regex = new Regex("([<])([^>]*)([>])", RegexOptions.Compiled);
        string test = "I'm walking on <sunshine>.";
        var match = _regex.Match(test);

Match is <sunshine> i guess you need to provide more code.

Regex is eager by default. Teach it to be lazy!

What I mean is, the * operator considers as many repetitions as possible (it's said to be eager). Use the *? operator instead, this tells Regex to consider as few repetitions as possible (ie to be lazy):

<.*?>

Because you are using parenthesis, you are creating matching groups. This is causing the match collection to match the groups created by the regular expression to also be matched. You can reduce your regular expression to [<][^>]*[>] and it will match only on the <text> that you wish.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM