Regexで最初にマッチした位置より後ろでマッチする部分を求める - C#

Regexで最初にマッチした位置より後ろでマッチする部分を求めるコードを紹介します。

概要

こちらの記事では正規表現を利用して文字列を検索するコードを紹介しました。 紹介したコードでは、正規表現式に一致する最初の部分を取得しますが、一致する部分が複数ある場合、最初に一致した場所の次の一致部分を求めたい場合があります。
Regex.NextMatch() メソッドを利用すると、最初に一致した以降の文字列でマッチする部分を求められます。

プログラム例1

UI

下図のフォームを作成します。テキストボックス、ボタン、MultilineプロパティをTrueに設定した複数行のテキストボックスを配置します。

コード

以下のコードを記述します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace RegexMatchNext
{
  public partial class FormMatchNextSimple : Form
  {
    public FormMatchNextSimple()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      string inputText = textBox1.Text;
      Regex reg = new Regex("pen");
      
      Match match = reg.Match(inputText);
      while (match.Success == true) {
        textBox2.Text += string.Format("{0:d}:{1:d} - {2}\r\n",match.Index, match.Length, match.Value);
        match = match.NextMatch();
      }
    }
  }
}

解説

Regexクラスのインスタンスオブジェクトを作成します。検索条件式には"pen"を与えます。
  string inputText = textBox1.Text;
  Regex reg = new Regex("pen");
     
  Match match = reg.Match(inputText);

Matchメソッドの戻り値のMatchオブジェクトのSuccessプロパティがtrue であれば、入力文字列に 検索条件に一致する部分があると判定し、一致した位置であるIndexプロパティの値、一致した部分の長さ、Lengthプロパティ、 一致した部分文字列のValueプロパティの値をテキストボックスに表示します。
一致した場合はさらに後方にも一致する箇所がある可能性があるため、NextMatch()メソッドを呼び出し、マッチした位置の後方を検索します。 マッチした場合は、Successプロパティがtrueとなるため、入力文字列でマッチする部分がある限り、whiieループを繰り返し、 一致する部分の情報をテキストボックスに表示します。
  while (match.Success == true) {
    textBox2.Text += string.Format("{0:d}:{1:d} - {2}\r\n",match.Index, match.Length, match.Value);
    match = match.NextMatch();
  }

実行結果

プロジェクトを実行します。下図のウィンドウが表示されます。


上部のテキストボックスに文字列を入力します。今回は"I have a pen and pencil" を入力します。


[button1]をクリックします。下部のテキストボックスに下図の結果が表示されます。
入力文字列中の"pen"の場所を検索します。10文字目と18文字目に"pen"の文字があります。 1文字目のインデックス番号を0とするため、"9:3"と"17:3"が結果として表示されます。


入力の文字列を "KoppenHoppenKeppen"にした場合の結果が下図です。 "pen"の文字が、4文字目、10文字目、16文字目にあります。 1文字目のインデックス番号を0とするため、"3:3"と"9:3"、"15:3"が結果として表示されます。

プログラム例2:量指定子で0回を含む任意個数が指定された場合

量子停止で0回を含む任意個数が指定された場合、動作が変化します。

UI

下図のフォームを作成します。button2とbutton3,button4 を利用します。

コード

以下のコードを記述します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace RegexMatchNext
{
  public partial class FormMatchNextSimple : Form
  {
    public FormMatchNextSimple()
    {
      InitializeComponent();
    }

    private void button2_Click(object sender, EventArgs e)
    {
      string inputText = textBox1.Text;
      Regex reg = new Regex("[0-9]+");

      Match match = reg.Match(inputText);
      while (match.Success == true) {
        textBox2.Text += string.Format("{0:d}:{1:d} - {2}\r\n", match.Index, match.Length, match.Value);
        match = match.NextMatch();
      }

    }

    private void button3_Click(object sender, EventArgs e)
    {
      string inputText = textBox1.Text;
      Regex reg = new Regex("[0-9]*");

      Match match = reg.Match(inputText);
      while (match.Success == true) {
        textBox2.Text += string.Format("{0:d}:{1:d} - {2}\r\n", match.Index, match.Length, match.Value);
        match = match.NextMatch();
      }

    }

    private void button4_Click(object sender, EventArgs e)
    {
      string inputText = textBox1.Text;
      Regex reg = new Regex("[0-9]?");

      Match match = reg.Match(inputText);
      while (match.Success == true) {
        textBox2.Text += string.Format("{0:d}:{1:d} - {2}\r\n", match.Index, match.Length, match.Value);
        match = match.NextMatch();
      }
    }
  }
}

解説

上部のテキストボックスに入力された文字列で検索します。
button2,button3,button4の検索する正規表現式は次の通りです。

button2

[0-9]+

button3

[0-9]*

button4

[0-9]?

実行結果

上記のプロジェクトを実行します。下図のウィンドウが表示されます。


上部のテキストボックスに文字列を入力します。今回は、"Penguin85Yen" を入力します。


[button2]をクリックします。[0-9]+で検索します。8文字目から2文字が該当しますので、"7:2"が結果として表示されます。


[button3]をクリックします。[0-9]*で検索します。*が設定されており、0文字以上のため、どんな文字でも結果にマッチします。 この場合、0番目から順番に長さ0文字で検索結果にマッチし、NextMatchで一文字進んだ位置から検索する動作になります。
7番目(8文字目)は2文字マッチし、マッチした次の文字(9番目)から検索が再開する動作となります。


[button4]をクリックします。[0-9]?で検索します。?が設定されており、0文字または1文字のため、どんな文字でも結果にマッチします。 この場合も、0番目から順番に長さ0文字で検索結果にマッチし、NextMatchで一文字進んだ位置から検索する動作になります。
7番目(8文字目)は1文字マッチし、8番目(9文字目)も1文字でマッチ、マッチした次の文字(9番目)から検索が再開する動作となります。


このページのキーワード
  • Regexで最初にマッチした位置より後ろでマッチする部分を取得する
著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
最終更新日: 2023-01-17
作成日: 2023-01-17
iPentec all rights reserverd.