Sprache を利用してセクション記号と複数のキー名と値を抽出するパーサーを作成する - C#

Sprache を利用してセクション記号と複数のキー名と値を抽出するパーサーのコードを紹介します。

プログラム

UI

下図のUIを作成します。複数行のテキストボックスを2つ、Buttonを1つ配置します。

コード

下記のコードを記述します。[button1]のClickイベントを実装しています。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Sprache;

namespace SimpleSprache
{
  public partial class FormSectionParse : Form
  {
    public class MySection
    {
      public string id;
      public string name;
      public IEnumerable<MyItem> myitems;

      public MySection(string mid, string mname, IEnumerable<MyItem> mmyitems)
      {
        id = mid;
        name = mname;
        myitems = mmyitems;
      }
    }

    public class MyItem
    {
      public string key;
      public string value;

      public MyItem(string mkey, string mvalue)
      {
        key = mkey;
        value = mvalue;
      }
    }

    public static readonly Parser<string> p_key = Parse.Letter.AtLeastOnce().Text().Token();
    public static readonly Parser<string> p_value = (from open in Parse.Char('"')
                                                     from content in Parse.CharExcept('"').Many().Text()
                                                     from close in Parse.Char('"')
                                                     select content).Token();

    public static readonly Parser<MyItem> p_key_value = from lk in p_key
                                                   from lv in p_value
                                                   select new MyItem(lk, lv);

    public static readonly Parser<MySection> section = from id in p_key
                                                       from title in p_value
                                                       from lbracket in Parse.Char('[').Token()
                                                       from key_value_s in p_key_value.Many()
                                                       from rbracket in Parse.Char(']').Token()
                                                       select new MySection(id, title, key_value_s);

    public FormSectionParse()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      string input = textBox1.Text;
      MySection section_item = section.Parse(input);
      textBox2.Text = string.Format("{0} : {1}\r\n", section_item.id, section_item.name);
      textBox2.Text += "-----\r\n";
      foreach (MyItem m in section_item.myitems) {
        textBox2.Text += string.Format("{0} : {1}\r\n", m.key, m.value);
      }

    }
  }
}

解説

メインのパーサーのコードは下記になります。
id title
[
  key1 value1
  key1 value1
  ...
  keyn valuen
]
の形式をパージングするコードです。複数個の要素を抽出する箇所は Many() メソッドを記述し複数の要素を検出できるようにします。
    public static readonly Parser<MySection> section = from id in p_key
                                                       from title in p_value
                                                       from lbracket in Parse.Char('[').Token()
                                                       from key_value_s in p_key_value.Many()
                                                       from rbracket in Parse.Char(']').Token()
                                                       select new MySection(id, title, key_value_s);

p_key_value部分は下記の記述になっており、key と value の組をパージングするコードになっています。
    public static readonly Parser<MyItem> p_key_value = from lk in p_key
                                                   from lv in p_value
                                                   select new MyItem(lk, lv);

パーサーの結果はMySectionオブジェクトで取得されます。MySectionオブジェクト内のid, nameをテキストボックスに表示します。また、MySectionオブジェクト内のmyitemsには複数のMyItemオブジェクトが格納されていますので、foreachループでMyItemsオブジェクトのkeyとvalueのペアをテキストボックスに表示します。
      string input = textBox1.Text;
      MySection section_item = section.Parse(input);
      textBox2.Text = string.Format("{0} : {1}\r\n", section_item.id, section_item.name);
      textBox2.Text += "-----\r\n";
      foreach (MyItem m in section_item.myitems) {
        textBox2.Text += string.Format("{0} : {1}\r\n", m.key, m.value);
      }

実行結果

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


上部のテキストボックスに下記の文字列を入力します。
Item "お気に入り"
[
  Penguin "Jump"
  Duck "Swim"
  Owl "Sleep"
]



[button1]をクリックすると結果が下記のテキストボックスに表示されます。id, title部分とセクション内部のkey, value の複数のペアが取り出せていることが確認できます。


著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
掲載日: 2018-01-09
iPentec all rights reserverd.