87993


C#で正規表現で行単位で取得するソースを組んでいたのですが

①`string text ="{\r\n{\r\n";`  
②`string text ="{\n{\n";`  
③`string text ="{\r{\r";`

[code]

    string[] lineLists2 = Regex.Split(text, "\n|\r\n|\r");
    string[] lineLists3 = Regex.Split(text, "(\n|\r\n|\r)");
    
    Regex regex = new Regex(".*[\n|\r\n|\r]");
    Match match = regex.Match(text, 0);
    
[/code]

を行うと、matchには  
①`{\r\n`  
②`{\n`  
となるのですが、③だけ出力値が  
③`{\r{\r`  
となり、Splitでは`\r`を認識しており、Matchのみが途中の`\r`を認識していないのですが  
理由をご存じの方ご教示願えないでしょうか  
また、`{\r`にする方法もご存じであれば重ねてご教示お願いします。

環境：Windows10、VS2022 Community


CC BY-SA 4.0
2022-03-23T10:56:59.807
87988
2022-03-23T12:49:03.647
2022-03-23T12:41:59.727
9820
42605
question
c# .net 正規表現
C#のRegexの正規表現の改行(\r)について


`\r`を認識していないのではなく、Regex.Matchの`.*`が直接の原因です。

正規表現の`.`は任意の一文字を表しますが、[`RegexOptions.Singleline`](https://docs.microsoft.com/ja-
jp/dotnet/standard/base-types/regular-expression-options#single-line-
mode)で単一行モードを指定しない場合は _任意の一文字から\nを除外_ します。  
つまり`.*`にマッチする範囲は`\n`の手前までなので、①では`{\r`、②では`{`となりますが、③では`{\r{\r`全体となります。  
上記の文字列に対して`.*[\r\n]`のような正規表現を使用すると、`*`は[最長一致の量指定子](https://docs.microsoft.com/ja-
jp/dotnet/standard/base-types/quantifiers-in-regular-
expressions)ですので可能な限り長い文字列を取得しようとします。  
その結果、③でマッチする結果は`{\r{\r`となってしまいます。

下記のようにRegex単一行モードとした場合は、①②も末尾までマッチします。  
`Regex regex = new Regex(@".*[\r\n]", RegexOptions.Singleline);`

最短一致の量指定子を使用する方法が`{\r`にマッチさせる簡潔な手段です。  
`.*`を`.*?`に書き換えることでご質問で意図する出力を得ることができます。

サンプルコード

[code]

    using System;
    using System.Text.RegularExpressions;
    
    namespace ConsoleApp1
    {
        class Program
        {
    
            static void Main(string[] args)
            {
                var texts = new string[]{ "{\r\n{\r\n", "{\n{\n" , "{\r{\r" };
                foreach(var text in texts)
                {
                    // Regex regex = new Regex(@".*[\r\n]");  // うまくいけてないコード
                    // Regex regex = new Regex(@".*?[\r\n]", RegexOptions.Singleline);  // 単一行モード
                    Regex regex = new Regex(@".*?[\r\n]", RegexOptions.Singleline);     // 単一行モードでも最短一致の量指定子ならばうまくいく
                    Match match = regex.Match(text, 0);
                    Console.WriteLine(match.Value);
                }
            }
        }
    }
    
[/code]


CC BY-SA 4.0
2022-03-23T12:41:28.267
87992
2022-03-23T12:41:28.267
9820
87988
answer


[ピリオド記号 (`.`) は、`\n` (改行文字、`\u000A`)
を除く任意の文字と一致](https://docs.microsoft.com/ja-jp/dotnet/standard/base-
types/character-classes-in-regular-expressions#any-
character-)すると定められているからです。つまり、`.`は`\r`にマッチします。  
`".*[\n|\r\n|\r]"`というパターンは`.`が`\r`にマッチしないことを期待した記述ではないでしょうか？  
`"[^\r\n]*[\n|\r\n|\r]"`なら期待する結果が得られると思います。

もちろん`Regex.Split`が期待通りの動作をするのは`.`を使っていないからです。


CC BY-SA 4.0
2022-03-23T12:49:03.647
87993
2022-03-23T12:49:03.647
4236
87988
answer