0

Say I have a situation where I need to search for the word 'Foo' in a document but I only want it to match if the word 'Bar' appears anywhere else in that document (i.e. 'Bar' can be on the same line, a different line, before or after 'Foo'). Can I use a Regular Expression to do this?

Following the link in this SE post, I've tried:

Foo(?=.*\nBar)|Foo(?=.*Bar)|Foo(?<!.*Bar)|Foo(?<!.*\nBar)

which works great if Foo is missing, but it still selects Foo even if Bar is missing. I've also checked this SE post, but all the answers speak of Java/Perl, and do not work using .NET.

Is it possible to accomplish this using Regular Expressions in .NET, or do I need to resort to using a C# && operator in the code itself?

Community
  • 1
  • 1
  • 5
    what's wrong with `str.Contains("Foo") && str.Contains("Bar")`? – Jonesopolis Nov 23 '15 at 22:39
  • 1
    Why do only want to use regular expressions? Are you using some sort of control that takes in a regex as a validation or something? – D Stanley Nov 23 '15 at 22:40
  • @DStanley I am using regular expressions in place of each string Foo and Bar. I just used string for clarity of the question as the actual regex expressions are very complex – user5596939 Nov 24 '15 at 14:16

2 Answers2

0

If I understand correctly your question, your code is almost good.

Try this :

    Foo(?=.*Bar)|Foo(?<=Bar.*)

It means :

Select from 2 alternatives :
    - Foo, then match a suffix (.*Bar) but exclude it from the capture
    - Foo, with a prefix (Bar.*) but exclude it from the capture

Hope it helps :-)

Marimout
  • 205
  • 4
  • 8
  • yes thank you. I just added the C# Singleline Option to account for multiple lines and it works perfectly – user5596939 Nov 24 '15 at 14:45
  • Edit: sorry not sure if I should make a new question for this, but this does work with Foo Bar, but not quite with what I actually need which is a regex and a word: 4\d{3}([\ \-]?)\d{4}\1\d{4}\1\d{4}(?=.*Bar)|4\d{3}([\ \-]?)\d{4}\1\d{4}\1\d{4}(?<=Bar.*). The regex checks for a Credit Card number. This works fine when it's a credit card number in front of Bar, but not when Bar is behind the CC#. Ex: Bar 4111 1111 1111 1111. Any thoughts? – user5596939 Nov 24 '15 at 15:47
  • your regex just posted will not work with your example, because if the first numbered capture does not succeed, then the alternate regex using that back-reference will also fail – Ric Gaudet Nov 24 '15 at 16:40
0

Not exactly sure what you are asking: do you want to return a match only if "foo" and "bar" are both in the document? If so, then

(?>.*foo.*bar)|(?>.*bar.*foo) 

works pretty well. Then in C# .Net use RegexOptions.Singleline so that the "." does not stop at an "\n".

Code example:

        string text = @"blah blah bar foo bar";
        string pattern = @"(?>.*foo.*bar)|(?>.*bar.*foo)";
        Match match = new Regex(pattern, RegexOptions.Singleline).Match(text);
        if (match.Success)
        {
            // do something
        }

But if that is what you want, then using the string contains method is much simpler.

EDIT: Based on your new comment, try this regex, using a named capture group to just capture the number:

((?<CCNum>4\d{3}[ -]?(\d{4}[ -]?){2}\d{4}).*Bar)|(.*Bar.*(?<CCNum>4\d{3}[ -]?(\d{4}[ -]?){2}\d{4}))

And usage:

        string text = @"Bar 4111-1111 1111 1111";
        string pattern = @"((?<CCNum>4\d{3}[ -]?(\d{4}[ -]?){2}\d{4}).*Bar)|(.*Bar.*(?<CCNum>4\d{3}[ -]?(\d{4}[ -]?){2}\d{4}))";
        long CCNum;
        Match match = new Regex(pattern, RegexOptions.Singleline).Match(text);
        if (match.Success)
        {
            if (Int64.TryParse (match.Groups["CCNum"].Value.Replace(" ", "").Replace("-",""),out CCNum));
            {
                // here is your clean CC Number
            }


        }
Ric Gaudet
  • 898
  • 6
  • 16
  • thanks so much it's really close. The only thing is I need it to select only the credit card number instead of both Bar and the CC Number (or anything in between). – user5596939 Nov 24 '15 at 17:21
  • That is why I defined the named capture group CCNum--It just gets the number. Then in your code, access the Match.Groups["CCNum"].Value property (or something very similar; just going from off the cuff here). Bar is matched but not captured. – Ric Gaudet Nov 24 '15 at 17:24