switem記法

概要

 switem記法は、テキストを解析し整形するスクリプトのための記法です。
 テキストの書式を差し替えるような加工ができます。
 一部の処理に clmapで定義したクロージャを使用できます。

 switem記法は tpacを利用したDSLです。tpacの詳細は tpacを参照してください。
 以下、tpac記法と重複する説明は省いています。

処理の流れ

 switem文書は二種類のハンドル(parse, format)とその配下のハンドルで構成されます。
 対象のテキストを解析(parse)して構造化し、整形(format)した上で再びテキストとして出力します。
 便宜上、対象のテキストから一部を切りとった行の集まりをチャンクと呼びます。

 parseハンドルにはテキストをどう解析するか記述します。
 テキストをチャンクに分割し、チャンクごとに名前を与えます。
 また、チャンク同士にツリー構造を持たせます。

 formatハンドルはテキストをどう整形するか記述します。
 指定した名前のチャンクに対し置換などの文字列加工処理をします。
 最後に各チャンクを連結し、出力します。

テキストハンドル

 parseハンドルで解析した結果はひとつのtpac文書として保持します。
 このtpac文書の宣言のタグは "doc"です。
 tpac文書を構成する各ハンドルを便宜上「テキストハンドル」と呼びます。
 テキストハンドルには以下の二種類があります。

宣言

 宣言のタグは「switem」です。
 可能な子要素は parse, formatハンドルです。
 以下のキーを指定できます。

parseハンドル

 parseハンドルは配下にテキストの解析方法を定義したハンドルを記述します。
 解析時はまず名前を省略した parseハンドルを参照します。
 再帰的な解析をするとき、名前を付与した parseハンドルを呼ぶことができます。
 以下のキーを指定できます。

parse操作ハンドル

 parseハンドル配下のハンドルを「parse操作ハンドル」と呼びます。
 parse操作ハンドルはすべて名前が必須です。
 以下のキーを指定できます。

onelineハンドル

 onelineハンドルは一行のみ解析します。

 特定の先頭記号で始まる一行、あるいは正規表現とマッチする一行を解析します。

 以下のキーを指定できます。どちらか一方だけを指定してください。
 両方を指定した場合、patternキーは無視されます。どちらも指定しなかった場合は解析エラーとなります。

 カバーハンドルに以下のキーを保持します。

encloseハンドル

 encloseハンドルは特定の開始行と終端行とで挟まれた行を解析します。

 まず開始行を探します。
 開始行がみつかったなら、その次行以降から終端行を探します。
 開始行の次行以降と終端行の間に他の開始行があった場合は入れ子と判断し、整合する終端行を探します。
 終端行がみつからなかった場合はエラーとします。

 以下のキーを指定できます。

 カバーハンドルに以下のキーを保持します。

indentハンドル

 indentハンドルはインデントされた行を解析します。

 先頭記号で行の先頭が開始する行を探します。
 次行以降、同じ先頭記号が続いているか確認します。
 同じ先頭記号が続く行をチャンクとして格納します。

 以下のキーを指定できます。

 カバーハンドルに以下のキーを保持します。

formatハンドル

 formatハンドルは配下にテキストの加工方法を定義したハンドルを記述します。
 加工時、まず名前を省略した formatハンドルを参照します。
 下位のチャンクについて加工するとき、名前を付与した formatハンドルを呼ぶことができます。

format操作ハンドル

 formatハンドル配下のハンドルを「format操作ハンドル」と呼びます。
 format操作ハンドルはすべて名前が必須です。
 以下のキーを指定できます。

 include, excludeキーで指定されたタグについて、カバーハンドル(チャンクハンドルなら上位のカバーハンドル)のタグが、以下の条件をどちらも満たすときに処理対象となります。

subformatハンドル

 subformatハンドルは整形に利用するformatハンドルを指定します。
 指定したカバーハンドルの下位のカバーハンドルの整形に用いる formatハンドルを指定します。
 指定がなければsubformatハンドルが属すformatハンドルを利用します。
 複数のsubformatハンドルで対象となるカバーハンドルの場合、それぞれのformatハンドルから整形処理がされてしまうことに注意してください。

 以下のキーを指定できます。

replaceハンドル

 replaceハンドルはチャンク内の固定文字列を置換します。
 処理対象はチャンクハンドルのみです。

 テキストで検索文字列、置換文字列をタブ区切りで指定します。
 改行区切りで検索文字列、置換文字列の組を複数指定できます。
 検索文字列と一致する文字列が複数あった場合、すべて置換します。

 以下は文字列「Hello」を「Goodbye」に、「テスト」を「試験」に置換する例です。

#>> replace
Hello	Goodbye
テスト	試験

reprexハンドル

 reprexハンドルは正規表現でチャンク内の文字列を置換します。
 処理対象はチャンクハンドルのみです。

 テキストで検索文字列、置換文字列をタブ区切りで指定します。
 改行区切りで検索文字列、置換文字列の組を複数指定できます。
 検索文字列と一致する文字列が複数あった場合、すべて置換します。
 各行の末尾に改行コードを追加して連結した文字列に対し置換します。
 このため改行を含む正規表現を指定することができます。

 以下は正規表現「H([\w+])」「W([\w+])」とマッチする文字列を「h$1」「w$1」に置換する例です。
 たとえば「Hello World」は「hello world」に置換します。

#>> reprex
H([\w+])	h$1
W([\w+])	w$1

callハンドル

 callハンドルはクロージャでチャンクを加工します。
 チャンクハンドル、カバーハンドルどちらも処理対象とします。

 チャンクをクロージャで加工します。
 またチャンクに対応するハンドルの、bgnキー、endキーの値を加工することもできます。

 以下のキーを指定できます。

 以下はタグ名「コラム」のカバーハンドルについて bgnキーを「【コラム:ここから】」に、endキーを「【コラム:ここまで】」に、このカバーハンドル配下のチャンクハンドルについてチャンクの末尾に「written by TARO」という行を追加する例です。

#>> call:コラム
#-include コラム
#-cover
{ def hndl ->
	hndl.bgn = '【コラム:ここから】'
	hndl.end = '【コラム:ここまで】'
}
#-chunk
{ def hndl ->
	return [ hndl.dflt, "written by TARO" ].flatten()
}

ナンバリング

 formatハンドルでの整形処理の前に、通し番号などのキーをテキストハンドルに追加します。
 具体的には以下のキーを追加します。

出力

 formatハンドルでの整形処理の後で出力処理をします。

 各チャンクハンドルのデフォルトキーに格納されたチャンクをツリー構造に沿って連結することで生成したテキストを出力します。
 このときチャンクを構成する各行の末尾にはシステム固有の改行コードを付与します。

 カバーハンドルについてキー毎に以下の処理をします。
 キーが未指定ならば、なにもしません。