Silny ToJa
Silny ToJa

Reputation: 2261

Checking if string contains pattern, with places ignored. And returning the index from which the items match

I have implemented such a method:

static void Main(string[] args)
{
    string s = "05 AA 06 15 14";
    var pattern1 = "05 AA";
    var pattern2 = "06 15";
    var pattern3 = "AA ** 15";
    var pattern4 = "15 14";
    Console.WriteLine(CheckTextContains2(s, pattern1));
    Console.WriteLine(CheckTextContains2(s, pattern2));
    Console.WriteLine(CheckTextContains2(s, pattern3));
    Console.WriteLine(CheckTextContains2(s, pattern4));
}
private static int CheckTextContains2(string text, string pattern)
{
    if (text.Length < pattern.Length)
        return -1;
    for (int i = 0; i < text.Length - pattern.Length +1; i++)
    {
        for (int j = 0; j < pattern.Length; j++)
        {
            if (pattern[j] == '*')
                continue;
            else if (text[j + i] != pattern[j])
                break;
            else if (j == pattern.Length -1)
                return i;
        }
    }
    return -1;
}

The method checks if the given pattern is in the string, but ignore chars "*" and return start index.

But it seems terribly suboptimal, Can I getting it by regex?

Upvotes: 1

Views: 245

Answers (2)

Sebastian Schumann
Sebastian Schumann

Reputation: 3446

Yes. You can use Regex.Match(s, pattern) to check for position. The only change in pattern3 is that you have to replace * by ..

The code might look like this:

string s = "05 AA 06 15 14";
var pattern1 = "05 AA";
var pattern2 = "06 15";
var pattern3 = "AA .. 15";
var pattern4 = "15 14";

var posP1 = Regex.Match(s, pattern1) is { Success: true } m1 ? m1.Index : -1;
var posP2 = Regex.Match(s, pattern2) is { Success: true } m2 ? m2.Index : -1;
var posP3 = Regex.Match(s, pattern3) is { Success: true } m3 ? m3.Index : -1;
var posP4 = Regex.Match(s, pattern4) is { Success: true } m4 ? m4.Index : -1;

Console.WriteLine(posP1);
Console.WriteLine(posP2);
Console.WriteLine(posP3);
Console.WriteLine(posP4);

The output is:

0
6
3
9

DEMO

Explanation:

A . in regex is a single character wildcard. All the other characters in your pattern doesn't affect the regex and will be used as fixed text to find. You have to be a bit carefully about chars like \[]{}.()*+. But if your pattern doesn't contain any of those regex will work like string.IndexOf().

The Regex.Match() method will return a Match instance that contains a property that has to be checked for Success. The sample code does it using pattern matching to be able to write it in one line.

Keep in mind that you should cache the regexes with this._pattern1Finder = new Regex(pattern1, RegexOptions.Compiled) to avoid the regex construction at every execution. The call will look like this._pattern1Finder.Match(s) is { ... instead of using the static Methods of Regex. This depends on how often you try to match the same patterns against various inputs.

Upvotes: 2

lidqy
lidqy

Reputation: 2453

If the contest is: the-shorter-the-better, I'd like to introduce:

private static int CheckTextContains(string text, string pattern)
    {
        if (text.Length >= pattern.Length) {
            for (var offset = 0; offset < text.Length - pattern.Length; offset++) {
                if (!pattern.Where((t, i) => '*' != t && t != text[i + offset]).Any())
                    return offset;
            }
        }
        return -1;
    }

which is a condensed and not really well-readable and maintainable version of:

private static int CheckTextContains(string text, string pattern)
    {
        if (text.Length >= pattern.Length) {
            for (var offset = 0; offset < text.Length - pattern.Length; offset++) {
                if (IsMatch(offset))
                    return offset;
            }
        }
        return -1;

        bool IsMatch(int offset) {
            for (var i = 0; i < pattern.Length; i++)
            {
                if ('*' != pattern[i] && pattern[i] != text[i+offset]))
                    return false;
            }
            return true;
        }
    }

Upvotes: 0

Related Questions