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を愛用