3

The documentation says:

Qualifier: $

Description: The match must occur at the end of the string or before \n at the end of the line or string.

Pattern example: -\d{3}$

Text match example: -333 in -901-333

I expected that the qualifier $ will match end-of-string when we use RegexOptions.Singleline and match end-of-line when we use RegexOptions.Multiline as follows:

using System;
using System.Text.RegularExpressions;
namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            var text = @"_
abc
123
do-re-me";
            var pat = @"\w+$";
            var re = new Regex(pat, RegexOptions.Multiline);
            var ms = re.Matches(text);
            var i = 0;
            foreach (Match m in ms)
                Console.WriteLine($"{i++}.  {m}");
            Console.ReadKey();
        }
    }
}

The above code (RegexOptions.Multiline) resulted in:

0.  me

I used both .Net framework 4.7.1 and .Net Core 2.0 with a Console App and got the same result.

I expected the result to be:

0.  _
1.  abc
2.  123
3.  me

Note that the ^ qualifier worked as expected. Matched the beginning of the line when using RegexOptions.Multiline and the beginning of the string when using RegexOptions.Singleline.

Can anyone explain the behavior of the $ qualifier?

TylerH
  • 20,799
  • 66
  • 75
  • 101
AviFarah
  • 327
  • 1
  • 10

2 Answers2

3

I predict you're writing this source code on a Windows machine... where the line endings - embedded in your verbatim string literal - are "\r\n", not "\n".

You're currently looking for a word character followed by a "\n" - which it won't find, because there's a "\r" in the way.

If you remove the "\r" characters first, it works as you expect it to:

text = text.Replace("\r", "");

Alternatively, just change the format of your source code to use "\n" instead of "\r\n" as the line ending. Or as a third option, don't use a verbatim string literal:

string text = "_\nabc\n123\ndo-re-me";

Any of these options will give you the result you expect.

This is one of the issues with verbatim string literals, unfortunately. It's particularly problematic if you're working with a source control system which automatically translates between formats when cloning :(

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
3

The other answer shed some light on this issue but you don't need to remove carriage returns from your string. It's cleared in documentation. You'd want to use \r?$ instead of $ alone:

If you use $ with the RegexOptions.Multiline option, the match can also occur at the end of a line. Note that $ matches \n but does not match \r\n (the combination of carriage return and newline characters, or CR/LF). To match the CR/LF character combination, include \r?$ in the regular expression pattern.

revo
  • 47,783
  • 14
  • 74
  • 117