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

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

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

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

正規表現

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

Q&A

解決済

5回答

1646閲覧

正規表現で入力文にマッチしたルールを取得したい

myonkiti

総合スコア11

C#

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

正規表現

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

0グッド

0クリップ

投稿2019/07/02 05:58

編集2019/07/02 10:09

前提・実現したいこと

C#のRegexで正規表現を使ったマッチングをしたいと思っています。

下記の表のようなデータがあり、入力データに対して一致した正規表現がどれなのかを取得したいです。

ID正規表現
1宮*県
2東京都
3(京都|大阪)府

データの数だけRegexを作って検索をすればよいですが、もう少しスマートなやり方が無いものかと思い、そもそも1つのRegexに複数Regexを一つにまとめてしまって、一致したルール自体を取得できれば良いのではと考えました。
例えば、以下のようなことがしたいです。

■ルール
(宮県)|(東京都)|((京都|大阪)府)
■入力文
宮城県
■ヒットしたルール
・宮

試したこと

データの数だけRegexを作成する方法

C#

1 2 public class RegDataClass 3 { 4 public int Id { set; get; } 5 public string RegexStr { set; get; } 6 } 7 8 9 class Program 10 { 11 static void Main(string[] args) 12 { 13 string inputText = "宮崎県"; 14 15 List<RegDataClass> dataClasses = new List<RegDataClass>() 16 { 17 new RegDataClass() 18 { 19 Id=1, 20 RegexStr="宮.県", 21 }, 22 new RegDataClass() 23 { 24 Id=2, 25 RegexStr="東京都", 26 }, 27 new RegDataClass() 28 { 29 Id=3, 30 RegexStr="(京都|大阪)府", 31 } 32 }; 33 List<Regex> regices = new List<Regex>(); 34 35 for (int i = 0; i < dataClasses.Count; i++) 36 { 37 regices.Add(new Regex(dataClasses[i].RegexStr)); 38 } 39 40 for (int i = 0; i < regices.Count; i++) 41 { 42 if (regices[i].IsMatch(inputText)) 43 { 44 Console.WriteLine($"ID={i + 1}でヒット"); 45 } 46 } 47 } 48 }

よろしくお願いいたします。

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

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

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

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

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

Zuishin

2019/07/02 07:15 編集

Match.Name かコールバックを使ってください。
myonkiti

2019/07/02 08:41

System.Text.RegularExpressions.MatchにNameというメソッドやメンバーは見当たりませんでした。確認するClassはこちらで合っているでしょうか?また、コールバックを使うとはどのように使うことを指しているでしょうか。念のため、例を書き直していますので実現したいことを再確認して頂けますと幸いです。
myonkiti

2019/07/02 10:10

キャプチャグループの名前になると、判定したいルールに括弧が入るたびに1個ずつずれていってしまうのでこちらで実現するのは難しそうです。
guest

回答5

0

個々のルールを括弧で囲めば、「何番目の部分文字列が空で無いか」で、「何番目のルールにマッチしたか」がわかります。

投稿2019/07/02 06:29

otn

総合スコア84555

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

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

myonkiti

2019/07/02 07:31

回答ありがとうございます。 「何番目の部分文字列が空で無いか」があまりピンとこなかったのですが、 括弧で囲うことにより、処理結果の配列でマッチしてない部分では空になって返ってくるから空じゃない位置がマッチした位置、のようなことなのかな、と理解しました。 一応括弧を入れてみて下記のようにしてみましたが、Matchesのメソッドで返ってくるものが一致したものだけだったので別のメソッドだったりするでしょうか。 ``` string s = "abbc"; Regex reg = new Regex($"(a(a|b)bc)|(efg)|(hij)"); var matches = reg.Matches(s); foreach (Match match in matches) { // 処理 } ``` ただ、別の回答者さんである通り処理的にダメそうなので、そもそもの結合方法もしくは分割したまま処理する形をもう少し考えてみます。 ありがとうございました。
guest

0

「hsrjabceh」に対して「(abc|efg|hij|h.*h)」ではマッチ箇所が競合するので
「abc」と「h.*h」の両方はヒットしません

投稿2019/07/02 06:13

yambejp

総合スコア114839

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

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

myonkiti

2019/07/02 06:36

回答ありがとうございます。例を修正しました。
guest

0

ベストアンサー

グループ名をつければ事足りると思っていましたが、そうではなさそうなので、次のコードを試してみてください。
グループのインデックスがずれないように (?:京都|大阪)府 と、無名グループを作っています。

C#

1using System; 2using System.Linq; 3using System.Text.RegularExpressions; 4 5namespace ConsoleApp1 6{ 7 class Program 8 { 9 static void Main(string[] args) 10 { 11 var patterns = new[] 12 { 13 "宮.県", 14 "東京都", 15 "(?:京都|大阪)府" 16 }; 17 var regex = new Regex(string.Join("|", patterns.Select(a => $"(^{a}$)"))); 18 while (true) 19 { 20 Console.WriteLine("文字列を入力してください。"); 21 string input = Console.ReadLine(); 22 var match = regex.Match(input); 23 if (!match.Success) break; 24 foreach (var group in match.Groups.Cast<Group>().Where(a => a.Success).Skip(1)) 25 { 26 Console.WriteLine(patterns[int.Parse(group.Name) - 1]); 27 } 28 } 29 Console.WriteLine("マッチしなかったので終了します。何かキーを押してください。"); 30 Console.ReadKey(); 31 } 32 } 33}

投稿2019/07/02 10:51

Zuishin

総合スコア28660

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

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

Zuishin

2019/07/02 10:52

しかし、結果として本当に正規表現が必要なんでしょうか? グループ名で事足りるのでは?
myonkiti

2019/07/03 04:53

回答ありがとうございます。 上記のソースで実行してみて、「group.Name」でエラーが出た時点で、.Net Frameworkのバージョンの違いによりNameプロパティが無かったということに気が付きました。(4.6.1で作っていました。) グループ名に関して、調べた際に結果を取得するためのものという印象が強く、グループ名自体を取得できないものだと思いこんでいました。(match.Groups["url"] のように使うだけだと思ってました) サンプルでいただいたように、マッチしたもののグループ名が取得できるのであれば、Zuishin さんがおっしゃる通り、グループ名で大丈夫だと思います。 ありがとうございました。
guest

0

C#よく知らないし、質問者氏の意図がつかめているか100%の自信はありませんが、

C#

1(a(a|b)?bc|efg|hij)?

のようにして$1,$2に期待した値が入っているか順次チェックしていけば済むんじゃないかという気がしました。

投稿2019/07/02 08:48

KojiDoi

総合スコア13671

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

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

0

他言語の仕様ですが、以下のサイトでデバッグしてみるとよく分かります。
https://regex101.com/

TOOLS -> Regex debugger

投稿2019/07/02 06:37

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

myonkiti

2019/07/02 07:26

回答ありがとうございます。 そもそも無理やりくっつけても中身で同じように処理されてるのであれば、分割しても同じって感じでしょうか。 そもそもの結合方法もしくは分割したまま処理する形をもう少し考えてみます。 ありがとうございました。
退会済みユーザー

退会済みユーザー

2019/07/02 08:10

> そもそも無理やりくっつけても中身で同じように処理されてるのであれば、分割しても同じって感じでしょうか。 いえ。そんな回答はしていません。 正規表現の挙動を見たいのであれば、リンク先でデバッグしてみると消費される様子か確認できるので、どこでマッチしたかわかると回答しました。
myonkiti

2019/07/02 08:18

なるほど。どのルールにヒットしたかで処理を変えたいので、ただ挙動を見たいだけではないです。
退会済みユーザー

退会済みユーザー

2019/07/02 09:02

あー理解しました。これはハズレ回答ですね^^; 一つづつ検証するのが正規表現を使用する場合の最も適切な解になると思います。 ただ、そもそも適用したいフィルタのルールは正規表現だけでも無いのでは? あまり詳しくないですけど、パーサをいくつか覗いてみるとやりたいことに近い処理が見つかる気がします。
myonkiti

2019/07/02 10:23

ありがとうございます。やはり1つずつ検証したほうが良いですかね。。。 一応ここでのルールは正規表現だけ作成する制限はかけているので正規表現だけで問題ないです。 パーサに関しては時間があるときに除いてみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問