正規表現をテストするWPFアプリ

正規表現を簡単にチェックできるWPFアプリ(GUIアプリ)を作成します。 実用性には乏しいですが、学習する上では少しは役に立つかもしれません。

完成図

アプリ概要

左上(textBox1)、右上(button)、左下(textBox2)、右下(textBox3) の4つにそれぞれGUIの部品が設置されています。
左上のテキストボックスに、正規表現を入力します。
左下のテキストボックスに、検索対象のテキストを入力します。
右上のボタンを押すと、検索結果が自動的に右下のテキストボックスに表示されます。

XAMLコード

「ファイル」→「新規作成」→「プロジェクト」→「WPFアプリ」を選択してプロジェクトを作成してください。 すると自動的に xamlファイル「MainWindow.xaml」とc#のファイル「MainWindow.xaml.cs」が作られていることが確認できます。 まず、xamlファイル「MainWindow.xaml」をチェックしましょう。

<Window x:Class=(途中省略.)>
<Grid></Grid>
</Window>
のように、すでにコードが入力されているはずですが、 このWindowタグで囲まれたGridの部分を以下で置き換えます。

<Grid Name="Grid1">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="3*"/>
        <ColumnDefinition Width="1*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="1*"/>
        <RowDefinition Height="5*"/>
    </Grid.RowDefinitions>
    <Button Content="実行" FontSize="20" Grid.Column="1" />
    <TextBox Name="textBox1" TextWrapping="Wrap" Text="\w+" FontSize="30"/>
    <TextBox Name="textBox2" Grid.Row="1" TextWrapping="Wrap" />
    <TextBox Name="textBox3" Grid.Column="1" Grid.Row="1" TextWrapping="Wrap"/>
</Grid>

これで実行すると(実行せずにデザインを見ることも可能)次のような画面があらわれるはずです。

XAMLコードの解説

Gridの説明から始めます。ここが一番難しいところですが、一番重要なところでもあります。
Gridとは格子状にGUIの部品を設置するためのものです。 今回は、2行×2列の格子を用意して、テキストボックス3個とボタン1個の合計4個をこの格子の中に入れていきます。

次は2行×2列の格子を用意するコードになります。

<Grid Name="Grid1">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="3*"/>
        <ColumnDefinition Width="1*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="1*"/>
        <RowDefinition Height="5*"/>
    </Grid.RowDefinitions>
</Grid>
「2列分の定義」を行うのが Grid.ColumnDefinitions の内部です。 ここに
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="1*"/>
と2回 ColumnDefinition がありますが、これで 2 列分のスペースが確保されます。 もし 3 列定義したい場合は、もう一つ ColumnDefinition を追加します。
Widthは幅の指定です。ここに「*」という記号が使われていますが、これは「比」でサイズを指定するという意味です。 今の場合では「3:1」の比で列幅を定めています。 行についても同様です。ColumnがRowに代わるだけです。

Gridの中にGUIの部品を設置する方法

あるGUIの部品をX行Y列に指定したい場合は、

< GUIの部品名 Grid.Row="X" Grid.Column="Y" />
と書きます。ただし行と列ともに番号は「0」から始まります。 また、これが省略された場合は、自動的に「0」の指定になります。 したがって、
<TextBox Name="textBox1" TextWrapping="Wrap" Text="\w+" FontSize="30"/>
は、Grid.RowもGrid.Columnも指定されていないので、自動的にどちらも「0」と解釈されます。つまり「0行0列」に配置されます。
Name はプログラム上の名前でこのように名前を付けると C# のコードから参照できるようになります。 TextWrapping="Wrap" はテキストの折り返し設定です。

c#のコード

これから、ボタンを押したときにの処理を記述していきます。 まず、

<Button Content="実行" FontSize="20" Grid.Column="1" Click="Button_Click"/>
Click=まで入力してタブキーを押すと自動的にButon_Clickというような名前のメソッドが「MainWindow.xaml.cs」に現れます。 ここに、ボタンがクリックされた処理を記述します。 「MainWindow.xaml.cs」に画面を切り替えて、usingディレクティブに、
using System.Text.RegularExpressions;
を加えて、次の内容を入力します。

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        string pattern = textBox1.Text;
        string text = textBox2.Text;
        Regex r = new Regex(pattern);
        var matches = r.Matches(text);
        StringBuilder result = new StringBuilder();
        foreach (Match item in matches)
        {
            result.Append(item.Value + "\r\n");
        }
        result.Append($"マッチした数:{matches.Count}");
        textBox3.Text = result.ToString();
    }
}

StringBuilder というものを使用していますが、これは文字列の書き換えを多く行うときに使用するものです。 簡単な処理では、かわりに string を使用しても問題ありません。また、Regexではインスタンスメソッドを利用していますが、 静的メソッドももちろん使用できます。
これで大体完成ですが、今のままだとなぜかテキストボックス内でリターンができません。 この点を解消し、ついでにフォントサイズも変更し、さらにテキストが長くなった時にスクロールバーが表示されるようにします。

完成コード(C#)

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        SetComponent();
    }
    private void SetComponent()
    {
        foreach (var item in Grid1.Children.OfType<TextBox>())
        {
            item.FontSize = 20;
            item.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
            item.AcceptsReturn = true;
        }
        textBox2.Text = "There are a lot of apples.";
    }
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        string pattern = textBox1.Text;
        string text = textBox2.Text;
        Regex r = new Regex(pattern);
        var matches = r.Matches(text);
        StringBuilder result = new StringBuilder();
        foreach (Match item in matches)
        {
            result.Append(item.Value + "\r\n");
        }
        result.Append($"マッチした数:{matches.Count}");
        textBox3.Text = result.ToString();
    }
}

InitializeComponent() は用意されているメソッドで、Windowの初期化を行います。
SetComponent() はここで定義した自作メソッドで、これも初期化処理を行うものとして定義しています。 具体的には、textBox1,textBox2,textBox3 の各要素に対して、

  • フォントサイズを 20 に指定.
  • リターンキーを受け付ける.
  • 文字があふれたとき、スクロールバーを表示.
という設定を SetComponent で行います。コードは以下の通りです。
foreach (var item in Grid1.Children.OfType<TextBox>())
{
    item.FontSize = 20;
    item.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
    item.AcceptsReturn = true;
}

Grid1.Children.OfType() では LINQ の機能を使用しています。 Grid1 とういのは、各種部品を設置した格子の名前です。この子要素を Grid1.Children で取得します。その中で、TextBox だけを取り出すのが OfType の部分です。 こうすることで、forech の item は TextBox のインスタンス全体を動くことになります。 つまり textBox1,textBox2,textBox3 のすべてをわたります。したがって、このように処理をまとめて記述することができます。

完成コード(XAML) ただし以下は Window タグの中に記述する必要があります.

<Grid Name="Grid1">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="3*"/>
        <ColumnDefinition Width="1*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="1*"/>
        <RowDefinition Height="5*"/>
    </Grid.RowDefinitions>
    <Button Content="実行" FontSize="20" Grid.Column="1" Click="Button_Click"/>
    <TextBox Name="textBox1" TextWrapping="Wrap" Text="\w+" />
    <TextBox Name="textBox2" Grid.Row="1" TextWrapping="Wrap" />
    <TextBox Name="textBox3" Grid.Column="1" Grid.Row="1" TextWrapping="Wrap" />
</Grid>