質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

正規表現

正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

Q&A

解決済

3回答

5070閲覧

C#の正規表現で任意個数のキャプチャを行う

selpo

総合スコア41

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

正規表現

正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

0グッド

0クリップ

投稿2017/06/14 12:35

編集2017/06/14 14:28

正規表現で以下のようなパターンを実装しました。

C#

1var reg = new Regex(@"^(?:([0-9]*),)*([0-9]*)$");

カンマで区切られた整数をキャプチャするのが目的です。ところが、

C#

1var m = reg.Match("12,345,6,123,4");

とすると、m.Groupsは

C#

1m.Groups = {"12,345,6,123,4", "123", "4"};

となってしまいます。最後に合致した部分しかキャプチャされていないようです。想定していた動作は、

C#

1m.Groups = {"12,345,6,123,4", "12", "345", "6", "123", "4"};

です。量指定子"*"によって丸括弧"()"によるキャプチャも繰り返して欲しいです。
こういうことは正規表現ではできないのでしょうか。

もちろん、この場合に限ればSplitで事足りますが、実際にやりたいのはもう少し複雑なので、できれば正規表現で実現してしまいたいです。


[追記]
例が簡単すぎたのでもう少し複雑にします(やりたいことに近づけます)。

C#

1var reg = new Regex(@"^(?:((?:\([0-9]+,[0-9]+\))+),)*((?:\([0-9]+,[0-9]+\))+)$"); 2var m = reg.Match("(1,23)(45,6),(3,5),(7,9)");

この結果がこうなって欲しいです。

C#

1//m.Groups = {"(1,23)(45,6),(3,5),(7,9)", "(1,23)(45,6)", "(3,5)", "(7,9)"}; // こうなってほしい 2m.Groups = {"(1,23)(45,6),(3,5),(7,9)", "(3,5)", "(7,9)"}; // こうなってしまう

区切り文字自体は単純(カンマ等)なのですが、区切られている要素にも区切り文字が入ってしまっているので、単純なSplitではできないように思います(区切り文字とみなすかどうかが文脈に依存する)。
現状は自分で括弧の対応を解析して要素の区切りかどうかを識別していますが、これを正規表現だけで実現したいです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

出来ないです。キャプチャの括弧は2つしかないので、それぞれに対して1つだけキャプチャされます。
動的に「N番目のキャプチャ」の番号が変化すると、m.Groupsのどこに求める結果が入っているのか分からないことになります。

実際にやりたいのはもう少し複雑なので、できれば正規表現で実現してしまいたいです。

おそらくは、マッチさせながら注目位置を進めていくようなことになるのでしょうかね。

投稿2017/06/14 14:15

otn

総合スコア84557

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

selpo

2017/06/14 14:38

ありがとうございます! 「それぞれに対して1つだけキャプチャされます。」 結果を見るとそうなっていて、しかも最後にマッチしたものがキャプチャされています。 どれがキャプチャされるかは仕様で決まっているのでしょうか。 「m.Groupsのどこに求める結果が入っているのか分からないことになります。 」 どこに結果が入るかはm.Groups.Countで調べられると思います。 ただ、 "hoge = [123,45,6] -> (ab;c;def)" とかで {"hoge","123","45","6","ab","c","def"} を拾いたいときなど、複数種類のグループが混在していると確かに不便になりそうですね。 そうすると、やはりMatch(String, Int32)を使って拾っていくのが一般的にはよさそうですね。
otn

2017/06/14 15:01

> 複数種類のグループが混在していると確かに不便になりそうですね。 そういうことです。
guest

0

Regex.Matchメソッドでは無く、このケースなら、Regex.Matchesメソッドではないでしょうか?

csharp

1static void Main(string[] args) 2{ 3 var source = "12,345,6,123,4"; 4 5 var ret = Regex.Matches(source, @"(\d+)"); 6 7 8 foreach (Match match in ret) 9 { 10 //必ず成功する入力前提。 11 Console.WriteLine(match.Groups[0]); 12 } 13}

String.Splitメソッドが使えそうにないなら、Regex.Splitメソッドを使ってみてはいかがでしょうか?

csharp

1 2static void UseSplit() 3{ 4 var source = "12,345,6,123,4"; 5 6 //RegexにもSplitは有るのでString.Splitより面倒なコトしたいならこちらがオススメ 7 var ret = Regex.Split(source, ","); 8 9 foreach (var s in ret) 10 { 11 Console.WriteLine(s); 12 } 13}

投稿2017/06/14 14:04

編集2017/06/14 14:05
Tokeiya3

総合スコア260

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

selpo

2017/06/14 14:31

ありがとうございます!なるほど、Matchesも使えそうですね。Regex.Splitは知っていました。ありがとうございます。 ただ、コメントにも書かれていますが、Matchesだと最初に全体がMatchするかどうかを別途各ひつようがあるように思います。 そうすると、個々の要素を切り出す正規表現と、全体を調べる正規表現を別々に書く必要がありますよね?
Tokeiya3

2017/06/15 03:39 編集

この辺は、どー考えるかによって変わるかと思います。 実際、Matchesだと、Matchのインスタンスを複数生成することになりますから、場合によっては、MatchでMatchするか否かの判定+Splitのコストの方が結果的に安い可能性はあります。 ただ、このあたりは本当にケースバイケースなので、想定されるサンプルをSplit+Mathのプロセスと、Matchesのみで検討してみてはいかがでしょうか?
guest

0

自己解決

C#

1var reg = new Regex(@"^(?:((?:\([0-9]+,[0-9]+\))+),)*((?:\([0-9]+,[0-9]+\))+)$"); 2var m = reg.Match("(1,23)(45,6),(3,5),(7,9)");

で正しく出来ていました。値の取り出し方が違っていただけでした。
m.Groups[1].Valueだと、最も右のキャプチャしか取り出せませんが、m.Groups[1].Capturesをみると、きちんと全てキャプチャされています。
つまり、上の例だと、

C#

1m.Groups[0].Captures = { "(1,23)(45,6),(3,5),(7,9)" }; 2m.Groups[1].Captures = { "(1,23)(45,6)", "(3,5)" }; 3m.Groups[2].Captures = { "(7,9)" };

のように取り出せます。

投稿2017/06/15 04:19

selpo

総合スコア41

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問