1

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?

Silny ToJa
  • 1,815
  • 1
  • 6
  • 20
  • Does this answer your question? [Matching strings with wildcard](https://stackoverflow.com/questions/30299671/matching-strings-with-wildcard) – Sinatr Jul 07 '21 at 12:39
  • @Sinatr No, in my case '*' ignore only one char. And I need know start index. – Silny ToJa Jul 07 '21 at 12:58
  • 2
    Yes. You can use `Regex.Match(s, pattern)` to check for position. The only change in `pattern3` is that you have to replace `*` by `.`. [DEMO](https://dotnetfiddle.net/8QZ2wR) A sample line that looks for a position might look like `var posP1 = Regex.Match(s, pattern1) is { Success: true } m1 ? m1.Index : -1;` – Sebastian Schumann Jul 07 '21 at 12:58
  • @SebastianSchumann: A great answer. Too bad that the OP won't be able to accept it since you accidentally posted it into the comment field... – Heinzi Jul 07 '21 at 13:20
  • @Heinzi It wasn't accidentally posted as a comment. This was intended. I hoped that someone took the idea and add a bit of context information arround that. – Sebastian Schumann Jul 07 '21 at 13:36

2 Answers2

2

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.

Sebastian Schumann
  • 3,204
  • 19
  • 37
0

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;
        }
    }
lidqy
  • 1,891
  • 1
  • 9
  • 11