0

I'm using a regexpattern to highlight a text matching a given search criteria in WPF. When the user types in San, my function creates a pattern as (San). The effect in my Application is that the search result display all hits containg "San" with the phrase "San" highlighted. However, if the search string contatins parentheses or backslash such as "San("

creating the regex crashes With 'too many or too few '(' or similar, as the pattern would be (San()

Creating the pattern With the Regex.Escape solves the crash, but it also Escapes the initial parentheses. I could manipulate the pattern string after creating the regex, but is there a more streamlined way to do this?

private IEnumerable<Inline> CreateInlines(string text, string[] highlights)
    {
        var pattern = string.Join("|", highlights
            .Where(highlight => !string.IsNullOrEmpty(highlight))
            .Select(highlight => "(" + highlight + ")")
            .ToArray());

        if (string.IsNullOrEmpty(pattern))
        {
            yield return new Run(text);
            yield break;
        }

        var regex = new Regex(Regex.Escape(pattern), RegexOptions.IgnoreCase);
        var matches = regex.Matches(text);

        if (matches.Count < 1)
        {
            yield return new Run(text);
            yield break;
        }

        int offset = 0;
        for (int i = 0; i < matches.Count; i++)
        {
            var match = matches[i];
            if (match.Index > offset)
            {
                int length = match.Index - offset;
                yield return new Run(text.Substring(offset, length));
                offset += length;
            }

            if (match.Length > 0)
            {
                yield return new Run(text.Substring(offset, match.Length)) { Foreground = HighlightBrush };
                offset += match.Length;
            }
        }

        if (offset < text.Length)
        {
            yield return new Run(text.Substring(offset));
        }
    }
1
  • The answer is: do not enclose the pattern with parentheses. Another point: you most probably can reduce this greatly if you just use Regex.Replace Commented Jan 11, 2018 at 8:06

1 Answer 1

1

Do the Regex.Escape here:

    var pattern = string.Join("|", highlights
        .Where(highlight => !string.IsNullOrEmpty(highlight))
        .Select(highlight => "(" + Regex.Escape(highlight) + ")")
        .ToArray());

Also, C# 6 has string interpolation:

    var pattern = string.Join("|", highlights
        .Where(highlight => !string.IsNullOrEmpty(highlight))
        .Select(highlight => $"({Regex.Escape(highlight)})")
        .ToArray());

In fact, you don't need the parentheses at all! You are not capturing anything (at least I don't see you use Groups in your code).

Sign up to request clarification or add additional context in comments.

1 Comment

Correct, the parentheses was remains from when use of groups was intended :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.