Web検索はbingがおすすめ!

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

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

プログラム

UI

下図のUIを作成します。複数行のテキストボックスを2つ、Buttonを2つ配置しますが利用するのはbutton2のみです。

コード

下記のコードを記述します。[button2]の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 MySections
    {
      public IEnumerable<MySection> sections;

      public MySections( IEnumerable<MySection> msections)
      {
        sections = msections;
      }
    }

    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 static readonly Parser<MySections> sections = section.Many().Select(sections => new MySections(sections)).End();

    public static readonly Parser<MySections> sectionsq = (from sec in section.Many()
                                                          select new MySections(sec)).End();
                                                          


    public FormSectionParse()
    {
      InitializeComponent();
    }

    private void button2_Click(object sender, EventArgs e)
    {
      string input = textBox1.Text;
      MySections sections_item = sections.Parse(input);

      foreach (MySection s in sections_item.sections) {
        textBox2.Text = string.Format("{0} : {1}\r\n", s.id, s.name);
        textBox2.Text += "-----\r\n";
        foreach (MyItem m in s.myitems) {
          textBox2.Text += string.Format("{0} : {1}\r\n", m.key, m.value);
        }
      }
    }
  }
}

解説

セクション単体の検出はこちらの記事で紹介しているセクション検出と同一のコードを利用しています。
複数のセクションを検出するパーサーは下記になります。今回はクエリ式の結果のEnd()メソッドを呼び出していますが、End()メソッドを呼び出すことで、入力文字列すべてをパージングさせます。
    public static readonly Parser<MySections> sectionsq = (from sec in section.Many()
                                                          select new MySections(sec)).End();

出力部分のコードは下記になります。パーサーの結果はMySections オブジェクトで返ります。MySectionオブジェクト内のsectionsに複数のMySectionオブジェクトが格納されているため、foreachループで取得します。さらにMySectionオブジェクトのmyitemsにMyItemオブジェクトが複数格納されているため、foreachループで、MyItemの値も取り出してテキストボックスに表示します。
  string input = textBox1.Text;
  MySections sections_item = sections.Parse(input);

  foreach (MySection s in sections_item.sections) {
    textBox2.Text += string.Format("{0} : {1}\r\n", s.id, s.name);
    textBox2.Text += "-----\r\n";
    foreach (MyItem m in s.myitems) {
      textBox2.Text += string.Format("{0} : {1}\r\n", m.key, m.value);
    }
    textBox2.Text += "\r\n";
  }

実行結果

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


上部のテキストボックスに入力します。今回の入力値は下記とします。
ItemA "お気に入り"
[
  Penguin "Jump"
  Duck "Swim"
]
ItemB "履歴"
[
  Owl "Sleep"
  Hawk "Hunt"
]


[button2]をクリックします。パージングが実行され下部のテキストボックスに結果が表示されます。入力した内容がパージングされていることが確認できます。

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