OS XのMS Wordでの法律文書起案用JXA(JavaScript for Automation)スクリプト

はじめに

 今まで、法律文書のナンバリングに応じてインデントを自動設定するために、LibreOffice Basicでマクロを作り(法律文書起案用mi文法定義スクリプトとOpenOffice系マクロ)、VBA(MS Word)でマクロを作り(法律文書起案用MS Word用VBAマクロ)、その都度ソースコードをこのブログに置いてきました。
 そして今回、OS X(Macの現行OS)に備わったJavaScriptによる自動化機能、JavaScript for Automation(JXA)で、MS Wordのドキュメントに対して同じことをするスクリプトを作ってみましたので、またソースコードを置いておきます。JXAはOS X10.10 Yosemiteから使えるようです。OS X付属のScript Editorというアプリに貼り付ければ使えます(デフォルトの言語はJavaScriptではなくAppleScriptになっていますので注意)。
 MS Office 2016 for MacはまだちゃんとVBAが使えないようで(アップデートで徐々に改善されています)、私の作ったVBAも動きません。それで私も結局ずっと2011版を使っていたのですが、このJXAスクリプトなら2016版に対しても使えるわけです。まあ、2016版、まだ大きいバグとかあって使いにくいですけどね……。
 ちなみにVBAの方もLibreOffice Basicの方もたまに手を入れていて、その都度ブログ記事も更新して新しいソースコードを載せています。この記事もそうなると思います。
 Pagesでも同じようなことができたらそっち使いたいところなんですが、できないようですね。MS OfficeはVBAでできることがだいたいOS Xの自動化機能でもできるようです。JavaScriptなら正規表現も使えるし良いですね。

仕様

 MS Wordの選択範囲を処理します。
 例えば、段落頭の「第1 」「3 」「(2)ア 」などに応じてインデントを自動設定します。それに続く段落が「  」で始まれば、インデントを引き継ぎます(ぶら下がりは1字分だけになります)。フォントサイズは12ポイント。
 「① 」「② 」と列挙される場合は、その箇所が周囲より下がります。それに続く段落が「  」で始まれば、列挙前のインデントに戻ります。
 スペースが2つで始まって2つで終わる段落は中央揃えになります。スペースが3つで始まって3つで終わる段落は中央揃えの14ポイントになります。4つなら16ポイント。スペースは全角なら全部全角、半角なら全部半角と揃っていなければ効きません。
 スペースが2つで始まって1つで終わる段落は右揃え。
 なんかもう仕様を書くのもめんどくさい程度に大きくなってきました……(LibreOffice Basicの方もVBAの方もだいたい同じ仕様にアップデートしてあります。どれか1つに専念した方がいいとは思いますが)。

更新履歴

・2015年10月29日10時30分頃
 テンプレートから新規ドキュメントを作成して、そのドキュメントにクリップボードの中身をペーストして、インデントを自動設定する、という一連の流れを1つのスクリプトを実行するだけでできるようにしました。
 テンプレートごとに実行スクリプトを別に置くために、インデント自動設定部分を関数にしてライブラリに定義を置いたので、単純にこの記事からScript Editorにコードをコピペすれば動くというものではなくなってしまいました。
 そのライブラリを使って選択範囲にインデントを自動設定するだけのスクリプトも置いておきます。
・2015年10月29日11時頃
 実効速度が速くならないかなと思って、ライブラリの、正規表現とのマッチを試す文字列を短く切り取ってみました。少し速くなったような、変わっていないような。
・2015年10月29日13時40分頃
 段落頭の「第n 」「第n条」がないドキュメントは「1 」がトップレヴェル(左インデントが0)になるようにしました。
・2015年10月29日16時00分頃
 段落頭が全角スペース2つになる場合の処理が、3つでも4つでも同じように効いてしまっていた不具合を修正。
・2015年10月30日3時40分頃
 「段落頭の「第n 」「第n条」がないドキュメントは「1 」がトップレヴェルになるように」の処理のバグフィックス。
・2015年10月30日21時頃
 「段落頭の「第n 」「第n条」がないドキュメントは「1 」がトップレヴェルになるように」の処理のさらなるバグフィックス。
・2015年10月30日22時頃
 テンプレートから新規……のスクリプトで少し無駄なことをしていた(パスの表現をわざわざわかりにくい形式にしていた)ので修正。
・2015年10月31日18時頃
 中央揃えの段落のフォントサイズをもう一段階増やしました。両側にスペース5個で18ポイント。
 「① 」「② 」……の箇所は、必ずしも①から始めなくてもよいようにしました。
・2015年11月1日3時頃
 クリップボードの中身をプレーンテキストにしてからペーストするようにしました。
・2015年11月1日13時頃
 クリップボードの中身をプレーンテキストにしてからペーストする処理が間違っていたので直しました。

ライブラリ

 ”~/Library/Script Libraries/”に置きます。Script Librariesがなかったら作ります。スクリプトファイル自体には私は”kianLibrary”という名前をつけて置いています。
 引数として渡されたオブジェクトに対してインデント設定をする”kianIndent”という関数が定義されています。

function kianIndent (selection) {

var Word = new Application('Microsoft Word');
var paras = selection.paragraphs;

//トップレヴェルが「第n 」「第n条」か「n 」かの判定
var docStr = Word.activeDocument.textObject.content();
if ( /^第[0-9]+ /.test( docStr ) || /^第[0-9]+条/.test( docStr ) || /\r第[0-9]+ /.test( docStr ) || /\r第[0-9]+条/.test( docStr ) ) {	
	var top = 0;
} else {
	var top = -12;
}

for (var i = 0; i < paras.length; i++) {

	var paraStr = paras[i].textObject.content();
	var paraStrL = paraStr.substring( 0 , 7 );
	var paraStrR = paraStr.substring( paraStr.length -7 );
		
	//段落頭が全角スペース2つで始まる場合は前段落と同じにする
	if ( /^  [^ ]/.test( paraStrL ) && /[^ ]\r/.test( paraStrR ) && !/^[①-⑨] /.test( paras[i].previousParagraph().textObject.content() ) ) {
		paras[i].firstLineIndent = -12
		paras[i].paragraphLeftIndent = paras[i].previousParagraph().paragraphLeftIndent();
		paras[i].alignment = "align paragraph left";
		paras[i].textObject.fontObject.fontSize = 12;
		paras[i].wordWrap = true;
	//ナンバリングの処理
	} else if ( /^第[0-9]+ /.test( paraStrL ) ) {
		paras[i].firstLineIndent = -24
		paras[i].paragraphLeftIndent = 24;
		paras[i].alignment = "align paragraph left";
		paras[i].textObject.fontObject.fontSize = 12;
		paras[i].wordWrap = true;
	} else if ( /^[0-9]+ /.test( paraStrL ) ) {
		paras[i].firstLineIndent = -12
		paras[i].paragraphLeftIndent = top + 24;
		paras[i].alignment = "align paragraph left";
		paras[i].textObject.fontObject.fontSize = 12;
		paras[i].wordWrap = true;
	} else if ( /^[0-9]+\([0-9]+\) /.test( paraStrL ) ) {
		paras[i].firstLineIndent = -24
		paras[i].paragraphLeftIndent = top + 36;
		paras[i].alignment = "align paragraph left";
		paras[i].textObject.fontObject.fontSize = 12;
		paras[i].wordWrap = true;
	} else if ( /^\([0-9]+\) /.test( paraStrL ) ) {
		paras[i].firstLineIndent = -12
		paras[i].paragraphLeftIndent = top + 36;
		paras[i].alignment = "align paragraph left";
		paras[i].textObject.fontObject.fontSize = 12;
		paras[i].wordWrap = true;
	} else if ( /^\([0-9]+\)[ア-ン] /.test( paraStrL ) ) {
		paras[i].firstLineIndent = -24
		paras[i].paragraphLeftIndent = top + 48;
		paras[i].alignment = "align paragraph left";
		paras[i].textObject.fontObject.fontSize = 12;
		paras[i].wordWrap = true;
	} else if ( /^[ア-ン]+ /.test( paraStrL ) ) {
		paras[i].firstLineIndent = -12
		paras[i].paragraphLeftIndent = top + 48;
		paras[i].alignment = "align paragraph left";
		paras[i].textObject.fontObject.fontSize = 12;
		paras[i].wordWrap = true;
	} else if ( /^[ア-ン]+\([ア-ン]+\) /.test( paraStrL ) ) {
		paras[i].firstLineIndent = -24
		paras[i].paragraphLeftIndent = top + 60;
		paras[i].alignment = "align paragraph left";
		paras[i].textObject.fontObject.fontSize = 12;
		paras[i].wordWrap = true;
	} else if ( /^\([ア-ン]+\) /.test( paraStrL ) ) {
		paras[i].firstLineIndent = -12
		paras[i].paragraphLeftIndent = top + 60;
		paras[i].alignment = "align paragraph left";
		paras[i].textObject.fontObject.fontSize = 12;
		paras[i].wordWrap = true;
	} else if ( /^\([ア-ン]+\)[a-z]+ /.test( paraStrL ) ) {
		paras[i].firstLineIndent = -24
		paras[i].paragraphLeftIndent = top + 72;
		paras[i].alignment = "align paragraph left";
		paras[i].textObject.fontObject.fontSize = 12;
		paras[i].wordWrap = true;
	} else if ( /^[a-z]+ /.test( paraStrL ) ) {
		paras[i].firstLineIndent = -12
		paras[i].paragraphLeftIndent = top + 72;
		paras[i].alignment = "align paragraph left";
		paras[i].textObject.fontObject.fontSize = 12;
		paras[i].wordWrap = true;
	} else if ( /^[a-z]+\([a-z]+\) /.test( paraStrL ) ) {
		paras[i].firstLineIndent = -24
		paras[i].paragraphLeftIndent = top + 84;
		paras[i].alignment = "align paragraph left";
		paras[i].textObject.fontObject.fontSize = 12;
		paras[i].wordWrap = true;
	} else if ( /^\([a-z]+\) /.test( paraStrL ) ) {
		paras[i].firstLineIndent = -12
		paras[i].paragraphLeftIndent = top + 84;
		paras[i].alignment = "align paragraph left";
		paras[i].textObject.fontObject.fontSize = 12;
		paras[i].wordWrap = true;
	//「① 」から「⑨ 」が列挙される場合は前段落より1字下げる
	} else if ( /^[①-⑨] /.test( paraStrL ) && !/^[①-⑨] /.test( paras[i].previousParagraph().textObject.content() ) ) {
		paras[i].firstLineIndent = -12
		paras[i].paragraphLeftIndent = paras[i].previousParagraph().paragraphLeftIndent() +12;
		paras[i].alignment = "align paragraph left";
		paras[i].textObject.fontObject.fontSize = 12;
		paras[i].wordWrap = true;
	} else if ( /^[①-⑨] /.test( paraStrL ) ) {
		paras[i].firstLineIndent = -12
		paras[i].paragraphLeftIndent = paras[i].previousParagraph().paragraphLeftIndent();
		paras[i].alignment = "align paragraph left";
		paras[i].textObject.fontObject.fontSize = 12;
		paras[i].wordWrap = true;
	//「① 」から「⑨ 」が列挙された後、「  」で始まる段落に続く場合は、列挙前のインデントに戻す
	} else if ( /^  [^ ]/.test( paraStrL ) && /[^ ]\r/.test( paraStrR ) && /^[①-⑨] /.test( paras[i].previousParagraph().textObject.content() ) ) {
		if ( !/^[①-⑨] /.test( paras[i].previousParagraph().previousParagraph().textObject.content() ) ) {
			paras[i].firstLineIndent = -12
			paras[i].paragraphLeftIndent = paras[i].previousParagraph().previousParagraph().paragraphLeftIndent();
			paras[i].alignment = "align paragraph left";
			paras[i].textObject.fontObject.fontSize = 12;
			paras[i].wordWrap = true;
		} else if ( !/^[①-⑨] /.test( paras[i].previousParagraph().previousParagraph().previousParagraph().textObject.content() ) ) {
			paras[i].firstLineIndent = -12
			paras[i].paragraphLeftIndent = paras[i].previousParagraph().previousParagraph().previousParagraph().paragraphLeftIndent();
			paras[i].alignment = "align paragraph left";
			paras[i].textObject.fontObject.fontSize = 12;
		} else if ( !/^[①-⑨] /.test( paras[i].previousParagraph().previousParagraph().previousParagraph().previousParagraph().textObject.content() ) ) {
			paras[i].firstLineIndent = -12
			paras[i].paragraphLeftIndent = paras[i].previousParagraph().previousParagraph().previousParagraph().previousParagraph().paragraphLeftIndent();
			paras[i].alignment = "align paragraph left";
			paras[i].textObject.fontObject.fontSize = 12;
		} else if ( !/^[①-⑨] /.test( paras[i].previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().textObject.content() ) ) {
			paras[i].firstLineIndent = -12
			paras[i].paragraphLeftIndent = paras[i].previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().paragraphLeftIndent();
			paras[i].alignment = "align paragraph left";
			paras[i].textObject.fontObject.fontSize = 12;
		} else if ( !/^[①-⑨] /.test( paras[i].previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().textObject.content() ) ) {
			paras[i].firstLineIndent = -12
			paras[i].paragraphLeftIndent = paras[i].previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().paragraphLeftIndent();
			paras[i].alignment = "align paragraph left";
			paras[i].textObject.fontObject.fontSize = 12;
		} else if ( !/^[①-⑨] /.test( paras[i].previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().textObject.content() ) ) {
			paras[i].firstLineIndent = -12
			paras[i].paragraphLeftIndent = paras[i].previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().paragraphLeftIndent();
			paras[i].alignment = "align paragraph left";
			paras[i].textObject.fontObject.fontSize = 12;
		} else if ( !/^[①-⑨] /.test( paras[i].previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().textObject.content() ) ) {
			paras[i].firstLineIndent = -12
			paras[i].paragraphLeftIndent = paras[i].previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().paragraphLeftIndent();
			paras[i].alignment = "align paragraph left";
			paras[i].textObject.fontObject.fontSize = 12;
		} else if ( !/^[①-⑨] /.test( paras[i].previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().textObject.content() ) ) {
			paras[i].firstLineIndent = -12
			paras[i].paragraphLeftIndent = paras[i].previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().paragraphLeftIndent();
			paras[i].alignment = "align paragraph left";
			paras[i].textObject.fontObject.fontSize = 12;
		} else if ( !/^[①-⑨] /.test( paras[i].previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().textObject.content() ) ) {
			paras[i].firstLineIndent = -12
			paras[i].paragraphLeftIndent = paras[i].previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().previousParagraph().paragraphLeftIndent();
			paras[i].alignment = "align paragraph left";
			paras[i].textObject.fontObject.fontSize = 12;
		}
	//契約書用条数
	} else if ( /^第[0-9]+条/.test( paraStrL ) ) {
		paras[i].firstLineIndent = -12
		paras[i].paragraphLeftIndent = 12;
		paras[i].alignment = "align paragraph left";
		paras[i].textObject.fontObject.fontSize = 12;
		paras[i].wordWrap = true;
	//Align等をスペースで指定する場合
	} else if ( ( /^  [^ ]/.test( paraStrL ) && /[^ ] \r/.test( paraStrR ) ) || ( /^  [^ ]/.test( paraStrL ) && /[^ ] \r/.test( paraStrR ) ) ) {
		paras[i].firstLineIndent = 0
		paras[i].paragraphLeftIndent = 0;
		paras[i].alignment = "align paragraph right";
		paras[i].textObject.fontObject.fontSize = 12;
		paras[i].wordWrap = true;
	} else if ( ( /^  [^ ]/.test( paraStrL ) && /[^ ]  \r/.test( paraStrR ) ) ||  ( /^  [^ ]/.test( paraStrL ) && /[^ ]  \r/.test( paraStrR ) ) ) {
		paras[i].firstLineIndent = 0
		paras[i].paragraphLeftIndent = 0;
		paras[i].alignment = "align paragraph center";
		paras[i].textObject.fontObject.fontSize = 12;
		paras[i].wordWrap = false;
	} else if ( ( /^   [^ ]/.test( paraStrL ) && /[^ ]   \r/.test( paraStrR ) ) || ( /^   [^ ]/.test( paraStrL ) && /[^ ]   \r/.test( paraStrR ) ) ) {
		paras[i].firstLineIndent = 0
		paras[i].paragraphLeftIndent = 0;
		paras[i].alignment = "align paragraph center";
		paras[i].textObject.fontObject.fontSize = 14;
		paras[i].wordWrap = false;
	} else if ( ( /^    [^ ]/.test( paraStrL ) && /[^ ]    \r/.test( paraStrR ) ) || ( /^    [^ ]/.test( paraStrL ) && /[^ ]    \r/.test( paraStrR ) ) ) {
		paras[i].firstLineIndent = 0
		paras[i].paragraphLeftIndent = 0;
		paras[i].alignment = "align paragraph center";
		paras[i].textObject.fontObject.fontSize = 16;
		paras[i].wordWrap = false;
	} else if ( ( /^     [^ ]/.test( paraStrL ) && /[^ ]     \r/.test( paraStrR ) ) || ( /^     [^ ]/.test( paraStrL ) && /[^ ]     \r/.test( paraStrR ) ) ) {
		paras[i].firstLineIndent = 0
		paras[i].paragraphLeftIndent = 0;
		paras[i].alignment = "align paragraph center";
		paras[i].textObject.fontObject.fontSize = 18;
		paras[i].wordWrap = false;
	//何とも一致しなかった場合のデフォルトの段落
	} else {
		paras[i].firstLineIndent = 0
		paras[i].paragraphLeftIndent = 0;
		paras[i].alignment = "align paragraph left";
		paras[i].textObject.fontObject.fontSize = 12;
		paras[i].wordWrap = true;
	}
}
}
テンプレートから新規ドキュメント→ペースト→インデント設定関数を実行、のスクリプト

 テンプレートから新規ドキュメントし、ペーストし、ドキュメント全体にインデント設定関数を実行するスクリプトです。
 "filepath = "の後の部分には使いたいMS Wordテンプレートのホームディレクトリからのパスを指定します。
 上記ライブラリに"kianLibrary"という名前を付けて置いてあることが前提になっています。別の名前を付ける場合は、"Library('kianLibrary')"の中身を変えます。

//使いたいMS Wordテンプレートのホームディレクトリからのパスを指定。
var filePath = '/Dropbox/kiansaiban.dotx';
//予め"~/Library/Script Libraries/"に"kianLibrary"を置いておく
kianLibrary = Library('kianLibrary');

//アプリケーションを変数に格納
var Finder = new Application('Finder');
Finder.includeStandardAdditions = true;
var Word = new Application('Microsoft Word');

//テンプレートから新規ドキュメントを作成しつつMS Wordを起動
var folderPath = Finder.pathTo( 'home folder', {from:'user domain'} );
var doc = Word.createNewDocument({attachedTemplate:folderPath+filePath});
Word.activate();

//クリップボードの中身をプレーンテキストにしてペースト
Word.pasteSpecial (doc.textObject,{dataType:'paste text'});
//ドキュメント全体に対してインデント設定
kianLibrary.kianIndent(doc.textObject);
選択範囲にインデント設定関数を実行するスクリプト

 上記ライブラリに"kianLibrary"という名前を付けて置いてあることが前提になっています。別の名前を付ける場合は、"Library('kianLibrary')"の中身を変えます。

kianLibrary = Library('kianLibrary');
var Word = new Application('Microsoft Word');

kianLibrary.kianIndent(Word.selection);

法律文書起案用MS Word用VBAマクロ

Office 2016 for Macがいつの間にか出ていた

 7月からOffice 2016 for Macが出ていたんですね。Office 365ユーザー向けで。気付いていませんでした。私(当事務所)はOffice 365 Businessを利用していますので、使えます。

良かったのでメインで使おうと思った

 早速、使ってみました。
 少し試してみたところ、弁護士用に配布されている書式(おそらくWindows版のMS Officeで作られたものでしょう)との互換性が、Office for Mac 2011と比べて良くなっているように思います。あと、UIが美しいです。
 私(当事務所)は他人が作った書式を利用するとき以外はLibreOfficeを使っていたのですが、これからはもうMS Officeをメインにしてもいいかな、と思いました。

私は今までLibreOfficeでマクロを使っていた

 LibreOfficeでは私はこういうマクロを作って(法律文書起案用mi文法定義スクリプトとOpenOffice系マクロ)使っていました。”第1 ”とか”1 ”とかの文字列に反応してインデントを自動設定するマクロです。まずテキストエディタ(具体的にはmi)で起案して(プレーンテキストですが、この際にもスクリプトで色分け表示されます)、それをLibreOfficeにコピペしてマクロでインデントをつけて提出するわけです。

VBAでMS Word用にマクロを作り直した

 MS Officeに移行するならVBAでマクロを作り直さないとな、と思って、昨日VBAの入門書を買ってきて勉強して、マクロを作ってみました。
 前回のLibreOffice用マクロでは”第1 ”等の文字列に反応してスタイルを指定するというものでした。しかし、それでは、テンプレートファイルと連携を取る必要があってちょっと使い勝手が悪く感じたので、今回はスタイルに依存せずに直接マクロからインデントを指定しています。あと前回は文書全体に処理をかけていましたが、今回は選択範囲だけです。
【2015年10月26日追記】
 LibreOffice用マクロの方を、この記事のMS Word用マクロとほぼ同じ仕様に書き換えました。
【2015年10月26日追記終わり】

ところが、今のバージョンでは使えなかった

 ところが!Office 2016 for MacではVBE(マクロの開発環境)周りを作り直そうとしているようですね。そしてまだ作っている途中のようで、今のバージョンのOffice 2016 for MacではVBEにほとんど機能がない状態です。それでも、一旦Office for Mac 2011でマクロを作って、それをコピペするなりしてOffice 2016 for Macに持ってくればいいんじゃないかな、と思って、Office for Mac 2011で作ってみたんですけど、なんか100行ぐらいしかペーストできなかったんですよね……。だから、一応作ったし機能は今までのLibreOffice用のやつより気に入っているんですが、まだ私は実務で使えていません。これからも当分使わないでしょう。なんだそれ。

仕様(平成27年10月25日に少し変更)

 一応説明しておきますが、”第1 ”とか”(1) ”とかで始まる段落とそれに続く全角スペース2個で始まる段落にはまあ法律文書として普通のインデントが付いて、フォントが12ポイントになります。段落頭のナンバリングは、原則として全角で、括弧は半角で、括弧内の英数字は半角です。
 全角又は半角の、スペースが2個で始まり1個で終わる段落は右に寄せられ、スペースが2個で始まり2個で終わる段落は真ん中に寄せられ、スペースが3個で始まり3個で終わる段落は真ん中に寄せられた上でフォントが14ポイントになり、スペースが4個で始まり4個で終わる段落は真ん中に寄せられた上でフォントが16ポイントになります。
 選択範囲が処理されます。

結語

 とりあえず当記事に置いておくので、参考にする人はしてください。
 私はまだ使っていないので、細かい調整は必要かもしれません。
 改良したらまたこの記事も書き直しに来ます。

【2015年10月25日追記】
 結局、このマクロ作って以来、MS Office for Mac 2011でこれを使って仕事しています。MS Office 2016 for MacのVBEはアップデートのたびに少しずつ機能が実装されているんですが、あまり多くの行を書けないのは直ってません。早く2016に完全移行したいです。

更新履歴

・2015年8月11日22時頃
 段落が何とも一致しなかった場合の処理を、最初に一律でやってしまうのではなく、一致があったかどうかをBoolean型の変数で管理して一致がなかった場合にだけ最後にやることにしました。
・2015年8月12日2時30分頃
 WordWrapの設定を追加することで、中央揃えにした時に文字が中央に来ない不具合を直しました。
・2015年10月25日22時頃
 Like演算子というものを今日知ったので、それで全面的に書き直しました。ついでに、何とも一致しなかった場合にデフォルトの段落になるようにして、段落頭に全角スペースが2つ並ぶと前段落と同じインデントがつく(前段落「第n 」の場合を除く)という仕様に変更しました。
・2015年10月26日2時頃
 Like演算子を使って最後の方の「Align等をスペースで指定する場合」を書き直して処理が無駄なく速くなるようにしました。
・2015年10月27日1時30分頃
 ElseIfを使って書き直しました。
・2015年10月27日19時20分頃
 「2(1) 」や「(3)ア 」等の表現に対応しました。
 「① 」〜「⑨ 」が列挙される際、①の前の段落と比較して1字下がるようにしました。
・2015年10月28日13時頃
 「① 」〜「⑨ 」が列挙された後、頭が「  」の段落に続くと、「① 」〜「⑨ 」が列挙される前のインデントに戻るようにしました。
・2015年10月29日22時30分頃
 スペースで指定する箇所のバグフィックス。


Sub Kian()

Dim para  As Paragraph
Dim paraStr As String

'選択範囲の各段落を取り出す
For Each para In Selection.Paragraphs
    
    paraStr = Left(para.Range, Len(para.Range) - 1)

    '段落頭がスペース2つで始まる場合は前段落と同じ状態にする
    If Left(paraStr, 2) = "  [! ]" And Right(paraStr, 1) Like "[! ]" Then
        para.FirstLineIndent = -12
        para.LeftIndent = para.Previous.LeftIndent
        para.Alignment = wdAlignParagraphLeft
        para.Range.Font.Size = 12
        para.WordWrap = True
    
    '段落頭文字と一致した場合の処理
    ElseIf Left(paraStr, 3) Like "第[1-9] " Or Left(paraStr, 4) Like "第[0-9][0-9] " Then
        para.FirstLineIndent = -24
        para.LeftIndent = 24
        para.Alignment = wdAlignParagraphLeft
        para.Range.Font.Size = 12
        para.WordWrap = True

    ElseIf Left(paraStr, 2) Like "[0-9] " Or Left(paraStr, 3) Like "[0-9][0-9] " Then
        para.FirstLineIndent = -12
        para.LeftIndent = 24
        para.Alignment = wdAlignParagraphLeft
        para.Range.Font.Size = 12
        para.WordWrap = True
    
    ElseIf Left(paraStr, 5) Like "[0-9]([0-9]) " Or Left(paraStr, 6) Like "[0-9]([0-9][0-9]) " Or Left(paraStr, 6) Like "[0-9][0-9]([0-9]) " Or Left(paraStr, 7) Like "[0-9][0-9]([0-9][0-9]) " Then
        para.FirstLineIndent = -24
        para.LeftIndent = 36
        para.Alignment = wdAlignParagraphLeft
        para.Range.Font.Size = 12
        para.WordWrap = True

    ElseIf Left(paraStr, 4) Like "([0-9]) " Or Left(paraStr, 5) Like "([0-9][0-9]) " Then
        para.FirstLineIndent = -12
        para.LeftIndent = 36
        para.Alignment = wdAlignParagraphLeft
        para.Range.Font.Size = 12
        para.WordWrap = True
        
    ElseIf Left(paraStr, 5) Like "([0-9])[ア-ン] " Or Left(paraStr, 6) Like "([0-9][0-9])[ア-ン] " Then
        para.FirstLineIndent = -24
        para.LeftIndent = 48
        para.Alignment = wdAlignParagraphLeft
        para.Range.Font.Size = 12
        para.WordWrap = True

    ElseIf Left(paraStr, 2) Like "[ア-ン] " Then
        para.FirstLineIndent = -12
        para.LeftIndent = 48
        para.Alignment = wdAlignParagraphLeft
        para.Range.Font.Size = 12
        para.WordWrap = True
        
    ElseIf Left(paraStr, 5) Like "[ア-ン]([ア-ン]) " Then
        para.FirstLineIndent = -24
        para.LeftIndent = 60
        para.Alignment = wdAlignParagraphLeft
        para.Range.Font.Size = 12
        para.WordWrap = True

    ElseIf Left(paraStr, 4) Like "([ア-ン]) " Then
        para.FirstLineIndent = -12
        para.LeftIndent = 60
        para.Alignment = wdAlignParagraphLeft
        para.Range.Font.Size = 12
        para.WordWrap = True
        
    ElseIf Left(paraStr, 5) Like "([ア-ン])[a-z] " Then
        para.FirstLineIndent = -24
        para.LeftIndent = 72
        para.Alignment = wdAlignParagraphLeft
        para.Range.Font.Size = 12
        para.WordWrap = True

    ElseIf Left(paraStr, 2) Like "[a-z] " Then
        para.FirstLineIndent = -12
        para.LeftIndent = 72
        para.Alignment = wdAlignParagraphLeft
        para.Range.Font.Size = 12
        para.WordWrap = True
        
    ElseIf Left(paraStr, 5) Like "[a-z]([a-z]) " Then
        para.FirstLineIndent = -24
        para.LeftIndent = 84
        para.Alignment = wdAlignParagraphLeft
        para.Range.Font.Size = 12
        para.WordWrap = True

    ElseIf Left(paraStr, 4) Like "([a-z]) " Then
        para.FirstLineIndent = -12
        para.LeftIndent = 84
        para.Alignment = wdAlignParagraphLeft
        para.Range.Font.Size = 12
        para.WordWrap = True
        
    '段落頭が「① 」ないし「⑨ 」の場合は前段落より1字下げる
    ElseIf Left(paraStr, 2) = "① " Then
        para.FirstLineIndent = -12
        para.LeftIndent = para.Previous.LeftIndent + 12
        para.Alignment = wdAlignParagraphLeft
        para.Range.Font.Size = 12
        para.WordWrap = True
        
    ElseIf Left(paraStr, 2) Like "[②-⑨] " Then
        para.FirstLineIndent = -12
        para.LeftIndent = para.Previous.LeftIndent
        para.Alignment = wdAlignParagraphLeft
        para.Range.Font.Size = 12
        para.WordWrap = True

    '契約書用条文番号
    ElseIf Left(paraStr, 3) Like "第[0-9]条" Or Left(paraStr, 4) Like "第[0-9][0-9]条" Then
        para.FirstLineIndent = -12
        para.LeftIndent = 12
        para.Alignment = wdAlignParagraphLeft
        para.Range.Font.Size = 12
        para.WordWrap = True

    'Align等を半角スペースで指定する場合
    ElseIf Left(paraStr, 3) Like "  [! ]" And Right(paraStr, 2) Like "[! ] " Then
        para.FirstLineIndent = 0
        para.LeftIndent = 0
        para.Alignment = wdAlignParagraphRight
        para.Range.Font.Size = 12
        para.WordWrap = True

    ElseIf Left(paraStr, 3) Like "  [! ]" And Right(paraStr, 3) Like "[! ]  " Then
        para.FirstLineIndent = 0
        para.LeftIndent = 0
        para.Alignment = wdAlignParagraphCenter
        para.Range.Font.Size = 12
        para.WordWrap = False

    ElseIf Left(paraStr, 4) Like "   [! ]" And Right(paraStr, 4) Like "[! ]   " Then
        para.FirstLineIndent = 0
        para.LeftIndent = 0
        para.Alignment = wdAlignParagraphCenter
        para.Range.Font.Size = 14
        para.WordWrap = False

    ElseIf Left(paraStr, 5) Like "    [! ]" And Right(paraStr, 5) Like "[! ]    " Then
        para.FirstLineIndent = 0
        para.LeftIndent = 0
        para.Alignment = wdAlignParagraphCenter
        para.Range.Font.Size = 16
        para.WordWrap = False

    'Align等を全角スペースで指定する場合
    ElseIf Left(paraStr, 3) Like "  [! ]" And Right(paraStr, 2) Like "[! ] " Then
        para.FirstLineIndent = 0
        para.LeftIndent = 0
        para.Alignment = wdAlignParagraphRight
        para.Range.Font.Size = 12
        para.WordWrap = True

    ElseIf Left(paraStr, 3) Like "  [! ]" And Right(paraStr, 3) Like "[! ]  " Then
        para.FirstLineIndent = 0
        para.LeftIndent = 0
        para.Alignment = wdAlignParagraphCenter
        para.Range.Font.Size = 12
        para.WordWrap = False

    ElseIf Left(paraStr, 4) Like "   [! ]" And Right(paraStr, 4) Like "[! ]   " Then
        para.FirstLineIndent = 0
        para.LeftIndent = 0
        para.Alignment = wdAlignParagraphCenter
        para.Range.Font.Size = 14
        para.WordWrap = False

    ElseIf Left(paraStr, 5) Like "    [! ]" And Right(paraStr, 5) Like "[! ]    " Then
        para.FirstLineIndent = 0
        para.LeftIndent = 0
        para.Alignment = wdAlignParagraphCenter
        para.Range.Font.Size = 16
        para.WordWrap = False

    '何とも一致しなかった場合はデフォルトの段落
    Else
        para.FirstLineIndent = 0
        para.LeftIndent = 0
        para.Alignment = wdAlignParagraphLeft
        para.Range.Font.Size = 12
        para.WordWrap = True

    End If
    
    '段落頭が「① 」ないし「⑨ 」の段落が終わった後の段落頭が「  」の段落のインデントをその前の状態に戻す
    If Not para.Previous Is Nothing Then
        If Left(paraStr, 3) Like "  [! ]" And Right(paraStr, 1) Like "[! ]" And Left(para.Previous.Range, 2) Like "[①-⑨] " Then
            If Not Left(para.Previous.Previous.Range, 2) Like "[①-⑨] " Then
                para.FirstLineIndent = -12
                para.LeftIndent = para.Previous.Previous.LeftIndent
                para.Alignment = wdAlignParagraphLeft
                para.Range.Font.Size = 12
                para.WordWrap = True
            ElseIf Not Left(para.Previous.Previous.Previous.Range, 2) Like "[①-⑨] " Then
                para.FirstLineIndent = -12
                para.LeftIndent = para.Previous.Previous.Previous.LeftIndent
                para.Alignment = wdAlignParagraphLeft
                para.Range.Font.Size = 12
                para.WordWrap = True
            ElseIf Not Left(para.Previous.Previous.Previous.Previous.Range, 2) Like "[①-⑨] " Then
                para.FirstLineIndent = -12
                para.LeftIndent = para.Previous.Previous.Previous.Previous.LeftIndent
                para.Alignment = wdAlignParagraphLeft
                para.Range.Font.Size = 12
                para.WordWrap = True
            ElseIf Not Left(para.Previous.Previous.Previous.Previous.Previous.Range, 2) Like "[①-⑨] " Then
                para.FirstLineIndent = -12
                para.LeftIndent = para.Previous.Previous.Previous.Previous.Previous.LeftIndent
                para.Alignment = wdAlignParagraphLeft
                para.Range.Font.Size = 12
                para.WordWrap = True
            ElseIf Not Left(para.Previous.Previous.Previous.Previous.Previous.Previous.Range, 2) Like "[①-⑨] " Then
                para.FirstLineIndent = -12
                para.LeftIndent = para.Previous.Previous.Previous.Previous.Previous.Previous.LeftIndent
                para.Alignment = wdAlignParagraphLeft
                para.Range.Font.Size = 12
                para.WordWrap = True
            ElseIf Not Left(para.Previous.Previous.Previous.Previous.Previous.Previous.Previous.Range, 2) Like "[①-⑨] " Then
                para.FirstLineIndent = -12
                para.LeftIndent = para.Previous.Previous.Previous.Previous.Previous.Previous.Previous.LeftIndent
                para.Alignment = wdAlignParagraphLeft
                para.Range.Font.Size = 12
                para.WordWrap = True
            ElseIf Not Left(para.Previous.Previous.Previous.Previous.Previous.Previous.Previous.Previous.Range, 2) Like "[①-⑨] " Then
                para.FirstLineIndent = -12
                para.LeftIndent = para.Previous.Previous.Previous.Previous.Previous.Previous.Previous.Previous.LeftIndent
                para.Alignment = wdAlignParagraphLeft
                para.Range.Font.Size = 12
                para.WordWrap = True
            ElseIf Not Left(para.Previous.Previous.Previous.Previous.Previous.Previous.Previous.Previous.Previous.Range, 2) Like "[①-⑨] " Then
                para.FirstLineIndent = -12
                para.LeftIndent = para.Previous.Previous.Previous.Previous.Previous.Previous.Previous.Previous.Previous.LeftIndent
                para.Alignment = wdAlignParagraphLeft
                para.Range.Font.Size = 12
                para.WordWrap = True
            ElseIf Not Left(para.Previous.Previous.Previous.Previous.Previous.Previous.Previous.Previous.Previous.Previous.Range, 2) Like "[①-⑨] " Then
                para.FirstLineIndent = -12
                para.LeftIndent = para.Previous.Previous.Previous.Previous.Previous.Previous.Previous.Previous.Previous.Previous.LeftIndent
                para.Alignment = wdAlignParagraphLeft
                para.Range.Font.Size = 12
                para.WordWrap = True
            End If
        End If
    End If
    
Next

End Sub

法律文書起案用mi文法定義スクリプトとOpenOffice系マクロ

はじめに

 以前、はてなブログで公開していた法律文書起案用mi文法定義スクリプトとOpenOffice系マクロ(の改良版)のソースコードをこっちに置いておきます。将来、検索でここに辿り着いた、同じことをしようとしている誰かの参考になるために。ちなみにそのブログはその1記事しかありません。それはそのうち閉鎖します。

テキストエディタmiで色分け表示

 OS X(Macの現行OS)用テキストエディタmiで起案中のプレーンテキストをこのように色分け表示

kianmi

するための文法定義スクリプトとして今私が使っているのが以下のとおり(2015年10月25日注:miバージョン2用です。3用はさらに下にあります)。私は、今はこれなしでは文章が書けません。
【2015年11月1日追記】
 こういうことするために、Header(見出し)機能があったんですね……今頃気がつきました。
 このスクリプトはもはやあまり価値がないので、記事の末尾に回します。
【2015年11月1日追記終わり】

OpenOffice系ワープロソフトでインデントをつけるためのマクロ

 私は今はLibreOfficeを使っています。
 司法修習生の頃はそれで良かったんですが、弁護士となると書式集がMS Word形式になっているのでMS Wordに乗り換えた方がいいかなあと最近思っています。
 段落冒頭と最後の文字列に対応してスタイルを適用します。例えば、上に載せたmiの画面のテキストが、以下のようになります。(2015年10月28日注:今はもっと美しくなるように改善していますが、画像を差し替えるのがめんどくさいので画像は昔のままになっています。)

kianlibre

 使っているソースコードは以下のとおり。


REM  *****  BASIC  *****

Sub Main

Dim oDoc as Object
Dim oText
Dim pt as Integer
pt = 35.2778
Dim proc as Integer
proc = 0
Dim paraStr as String

oDoc = ThisComponent
oText = oDoc.Text

oSelections = oDoc.getCurrentSelection() 
oSel = oSelections.getByIndex(0)    

oPE = oSel.createEnumeration()

Do While oPE.hasMoreElements()
	oPar = oPE.nextElement()
	If oPar.supportsService("com.sun.star.text.Paragraph") Then 
		paraStr = oPar.String
		
		'段落頭が全角スペース2つで始まらない場合はproc=0にする
		'段落頭が全角スペース2つで始まる場合又は「② 」等で始まる場合はprocの値が変わらないので前段落と同じになる
		If Not ( Left ( paraStr , 3 ) Like "  [! ]" And Right( paraStr, 1 ) Like "[! ]" ) And Not ( Left ( paraStr , 2 ) Like "[①-⑨] " ) Then
			proc = 0
		End If
		
		'「① 」で始まる場合は前段落より1字下げる
		If Left(paraStr,2)  = "① " Then
			proc = proc + 1
		End If

		'段落頭がマッチする場合
		If Left( paraStr, 3 ) Like "第[0-9] " Or Left( paraStr, 4 ) Like "第[0-9][0-9] " Then
			oPar.ParaLeftMargin = 24*pt
			oPar.ParaFirstLineIndent = -24*pt
			oPar.ParaAdjust = 0
			oPar.CharHeightAsian = 12
			proc = 2

		ElseIf Left( paraStr, 2 ) Like "[0-9] " Or Left( paraStr, 3 ) Like "[0-9][0-9] " Or proc = 2 Then
			oPar.ParaLeftMargin = 24*pt
			oPar.ParaFirstLineIndent = -12*pt
			oPar.ParaAdjust = 0
			oPar.CharHeightAsian = 12
			proc = 2
			
		ElseIf Left( paraStr, 5 ) Like "[0-9]([0-9]) " Or Left( paraStr, 6 ) Like "[0-9]([0-9][0-9]) " Or Left( paraStr, 6 ) Like "[0-9][0-9]([0-9]) " Or Left( oPar.String, 7 ) Like "[0-9][0-9]([0-9][0-9]) " Then
			oPar.ParaLeftMargin = 36*pt
			oPar.ParaFirstLineIndent = -24*pt
			oPar.ParaAdjust = 0
			oPar.CharHeightAsian = 12
			proc = 3

		ElseIf Left( paraStr, 4 ) Like "([0-9]) " Or Left( paraStr, 5 ) Like "([0-9][0-9]) " Or proc = 3 Then
			oPar.ParaLeftMargin = 36*pt
			oPar.ParaFirstLineIndent = -12*pt
			oPar.ParaAdjust = 0
			oPar.CharHeightAsian = 12
			proc = 3
			
		ElseIf Left( paraStr, 5 ) Like "([0-9])[ア-ン] " Or Left( paraStr, 8 ) Like "([0-9])([0-9])[ア-ン] " Then
			oPar.ParaLeftMargin = 48*pt
			oPar.ParaFirstLineIndent = -24*pt
			oPar.ParaAdjust = 0
			oPar.CharHeightAsian = 12
			proc = 4

		ElseIf Left( paraStr, 2 ) Like "[ア-ン] " Or proc = 4 Then
			oPar.ParaLeftMargin = 48*pt
			oPar.ParaFirstLineIndent = -12*pt
			oPar.ParaAdjust = 0
			oPar.CharHeightAsian = 12
			proc = 4
			
		ElseIf Left( paraStr, 5 ) Like "[ア-ン]([ア-ン]) " Then
			oPar.ParaLeftMargin = 60*pt
			oPar.ParaFirstLineIndent = -24*pt
			oPar.ParaAdjust = 0
			oPar.CharHeightAsian = 12
			proc = 5

		ElseIf Left( paraStr, 4 ) Like "([ア-ン]) " Or proc = 5 Then
			oPar.ParaLeftMargin = 60*pt
			oPar.ParaFirstLineIndent = -12*pt
			oPar.ParaAdjust = 0
			oPar.CharHeightAsian = 12
			proc = 5
			
		ElseIf Left( paraStr, 5 ) Like "([ア-ン])[a-z] " Then
			oPar.ParaLeftMargin = 72*pt
			oPar.ParaFirstLineIndent = -24*pt
			oPar.ParaAdjust = 0
			oPar.CharHeightAsian = 12
			proc = 6

		ElseIf Left( paraStr, 2 ) Like "[a-z] " Or proc = 6 Then
			oPar.ParaLeftMargin = 72*pt
			oPar.ParaFirstLineIndent = -12*pt
			oPar.ParaAdjust = 0
			oPar.CharHeightAsian = 12
			proc = 6
			
		ElseIf Left( paraStr, 5 ) Like "[a-z]([a-z]) " Then
			oPar.ParaLeftMargin = 84*pt
			oPar.ParaFirstLineIndent = -24*pt
			oPar.ParaAdjust = 0
			oPar.CharHeightAsian = 12
			proc = 7

		ElseIf Left( paraStr, 4 ) Like "([a-z]) " Or proc = 7 Then
			oPar.ParaLeftMargin = 84*pt
			oPar.ParaFirstLineIndent = -12*pt
			oPar.ParaAdjust = 0
			oPar.CharHeightAsian = 12
			proc = 7
			
		ElseIf proc = 8 Then
			oPar.ParaLeftMargin = 96*pt
			oPar.ParaFirstLineIndent = -12*pt
			oPar.ParaAdjust = 0
			oPar.CharHeightAsian = 12
			proc = 8
			
		'契約書用条文番号
		ElseIf Left( paraStr, 3 ) Like "第[0-9]条" Or Left( paraStr, 4 ) Like "第[0-9][0-9]条" Or proc = 9 Then
			oPar.ParaLeftMargin = 12*pt
			oPar.ParaFirstLineIndent = -12*pt
			oPar.ParaAdjust = 0
			oPar.CharHeightAsian = 12
			proc = 9

		'paraAdjust等を半角スペースで指定する場合
		ElseIf Left( paraStr, 3 ) Like "  [! ]" And Right( paraStr, 2 ) Like "[! ] " Then
			oPar.ParaLeftMargin = 0
			oPar.ParaFirstLineIndent = 0
			oPar.ParaAdjust = 1
			oPar.CharHeightAsian = 12
			proc = 10
	
		ElseIf Left( paraStr, 3 ) Like "  [! ]" And Right( paraStr, 3 ) Like "[! ]  " Then
			oPar.ParaLeftMargin = 0
			oPar.ParaFirstLineIndent = 0
			oPar.ParaAdjust = 3
			oPar.CharHeightAsian = 12
			proc = 10

		ElseIf Left( paraStr, 4 ) Like "   [! ]" And Right( paraStr, 4 ) Like "[! ]   " Then
			oPar.ParaLeftMargin = 0
			oPar.ParaFirstLineIndent = 0
			oPar.ParaAdjust = 3
			oPar.CharHeightAsian = 14
			proc = 10

		ElseIf Left( paraStr, 5 ) Like "    [! ]" And Right( paraStr, 5 ) Like "[! ]    " Then
			oPar.ParaLeftMargin = 0
			oPar.ParaFirstLineIndent = 0
			oPar.ParaAdjust = 3
			oPar.CharHeightAsian = 16
			proc = 10

		'paraAdjust等を全角スペースで指定する場合
		ElseIf Left( paraStr, 3 ) Like "  [! ]" And Right( paraStr, 2 ) Like "[! ] " Then
			oPar.ParaLeftMargin = 0
			oPar.ParaFirstLineIndent = 0
			oPar.ParaAdjust = 1
			oPar.CharHeightAsian = 12
			proc = 10
	
		ElseIf Left( paraStr, 3 ) Like "  [! ]" And Right( paraStr, 3 ) Like "[! ]  " Then
			oPar.ParaLeftMargin = 0
			oPar.ParaFirstLineIndent = 0
			oPar.ParaAdjust = 3
			oPar.CharHeightAsian = 12
			proc = 10
	
		ElseIf Left( paraStr, 4 ) Like "   [! ]" And Right( paraStr, 4 ) Like "[! ]   " Then
			oPar.ParaLeftMargin = 0
			oPar.ParaFirstLineIndent = 0
			oPar.ParaAdjust = 3
			oPar.CharHeightAsian = 14
			proc = 10

		ElseIf Left( paraStr, 5 ) Like "    [! ]" And Right( paraStr, 5 ) Like "[! ]    " Then
			oPar.ParaLeftMargin = 0
			oPar.ParaFirstLineIndent = 0
			oPar.ParaAdjust = 3
			oPar.CharHeightAsian = 16
			proc = 10

		'デフォルトの段落
		ElseIf proc = 0 then
			oPar.ParaLeftMargin = 0
			oPar.ParaFirstLineIndent = 0
			oPar.ParaAdjust = 0
			oPar.CharHeightAsian = 12
			proc = 0
		End If
		
		'今回paraAdjust等をスペースで指定したら次回はデフォルトから出発
		If proc = 10 then
			proc = 0
		End If
		
	end if
Loop

End Sub

更新履歴

・2015年10月26日更新
 Like演算子というものを知ったので、全面的に書き直しました。今回のバージョンではスタイルを使わずにマクロから直接インデント等を設定します。前回のバージョンでは文書全体を処理しましたが、今回のバージョンでは選択範囲だけ処理します。
 なお、こっちの記事(法律文書起案用MS Word用VBAマクロ)にあるMS Word用マクロとだいたい同じ処理になるようにしました。
・2015年10月27日午前更新
 ElseIfで書き直しました。
・2015年10月27日午後更新
 「2(1) 」や「(3)ア 」等の表現に対応しました。
 ①〜⑨が列挙される際、①の前の段落と比較して1字下がるようにしました。
・2015年10月29日更新
 スペースで指定する場合のバグフィックス。

おわりに

 色分けがないとソースコード貼ったときに不格好ですね。WordPressでもプラグインを入れれば簡単にできるようですが、ここはプログラミングのブログではないのでそこまではしません。

miの文法定義スクリプト


GlobalAttribute_SDFVersion("1.0")
GlobalAttribute_SDFName("kian")

state(idle)
{
	StateAttribute_Stable
	StateAttribute_DisableAllCategory
	StateAttribute_DefaultColor("000000")
	{lineend,{ChangeState(gyoto)}}
}

state(gyoto)
{
	StateAttribute_DefaultColor("000000")
	{"第1 ",{ChangeState(dai)}}
	{"第2 ",{ChangeState(dai)}}
	{"第3 ",{ChangeState(dai)}}
	{"第4 ",{ChangeState(dai)}}
	{"第5 ",{ChangeState(dai)}}
	{"第6 ",{ChangeState(dai)}}
	{"第7 ",{ChangeState(dai)}}
	{"第8 ",{ChangeState(dai)}}
	{"第9 ",{ChangeState(dai)}}
	{"第1条 ",{ChangeState(dai)}}
	{"第2条 ",{ChangeState(dai)}}
	{"第3条 ",{ChangeState(dai)}}
	{"第4条 ",{ChangeState(dai)}}
	{"第5条 ",{ChangeState(dai)}}
	{"第6条 ",{ChangeState(dai)}}
	{"第7条 ",{ChangeState(dai)}}
	{"第8条 ",{ChangeState(dai)}}
	{"第9条 ",{ChangeState(dai)}}
	{"第10条 ",{ChangeState(dai)}}
	{"第11条 ",{ChangeState(dai)}}
	{"第12条 ",{ChangeState(dai)}}
	{"第13条 ",{ChangeState(dai)}}
	{"第14条 ",{ChangeState(dai)}}
	{"第15条 ",{ChangeState(dai)}}
	{"第16条 ",{ChangeState(dai)}}
	{"第17条 ",{ChangeState(dai)}}
	{"第18条 ",{ChangeState(dai)}}
	{"第19条 ",{ChangeState(dai)}}
	{"第20条 ",{ChangeState(dai)}}
	{"第21条 ",{ChangeState(dai)}}
	{"第22条 ",{ChangeState(dai)}}
	{"第23条 ",{ChangeState(dai)}}
	{"第24条 ",{ChangeState(dai)}}
	{"第25条 ",{ChangeState(dai)}}
	{"第26条 ",{ChangeState(dai)}}
	{"第27条 ",{ChangeState(dai)}}
	{"第28条 ",{ChangeState(dai)}}
	{"第29条 ",{ChangeState(dai)}}
	{"1 ",{ChangeState(suu)}}
	{"2 ",{ChangeState(suu)}}
	{"3 ",{ChangeState(suu)}}
	{"4 ",{ChangeState(suu)}}
	{"5 ",{ChangeState(suu)}}
	{"6 ",{ChangeState(suu)}}
	{"7 ",{ChangeState(suu)}}
	{"8 ",{ChangeState(suu)}}
	{"9 ",{ChangeState(suu)}}
	{"(1) ",{ChangeState(kakkosuu)}}
	{"(2) ",{ChangeState(kakkosuu)}}
	{"(3) ",{ChangeState(kakkosuu)}}
	{"(4) ",{ChangeState(kakkosuu)}}
	{"(5) ",{ChangeState(kakkosuu)}}
	{"(6) ",{ChangeState(kakkosuu)}}
	{"(7) ",{ChangeState(kakkosuu)}}
	{"(8) ",{ChangeState(kakkosuu)}}
	{"(9) ",{ChangeState(kakkosuu)}}
	{"ア ",{ChangeState(kana)}}
	{"イ ",{ChangeState(kana)}}
	{"ウ ",{ChangeState(kana)}}
	{"エ ",{ChangeState(kana)}}
	{"オ ",{ChangeState(kana)}}
	{"カ ",{ChangeState(kana)}}
	{"キ ",{ChangeState(kana)}}
	{"ク ",{ChangeState(kana)}}
	{"ケ ",{ChangeState(kana)}}
	{"(ア) ",{ChangeState(kakkokana)}}
	{"(イ) ",{ChangeState(kakkokana)}}
	{"(ウ) ",{ChangeState(kakkokana)}}
	{"(エ) ",{ChangeState(kakkokana)}}
	{"(オ) ",{ChangeState(kakkokana)}}
	{"(カ) ",{ChangeState(kakkokana)}}
	{"(キ) ",{ChangeState(kakkokana)}}
	{"(ク) ",{ChangeState(kakkokana)}}
	{"(ケ) ",{ChangeState(kakkokana)}}
	{default,{ChangeState(idle)}}
	{lineend,{ChangeState(gyoto)}}
}

state(dai)
{
	StateAttribute_DefaultColor("FF0000")
	{lineend,{ChangeState(gyoto)}}
}

state(suu)
{
	StateAttribute_DefaultColor("DD00DD")
	{lineend,{ChangeState(gyoto)}}
}

state(kakkosuu)
{
	StateAttribute_DefaultColor("0000FF")
	{lineend,{ChangeState(gyoto)}}
}

state(kana)
{
	StateAttribute_DefaultColor("00AA00")
	{lineend,{ChangeState(gyoto)}}
}

state(kakkokana)
{
	StateAttribute_DefaultColor("DD8800")
	{lineend,{ChangeState(gyoto)}}
}

state(sonota)
{
	StateAttribute_DefaultColor("000000")
	{lineend,{ChangeState(gyoto)}}
}

miバージョン3用スクリプト(2015年10月5日以降更新)

・2015年10月5日更新
 miのバージョン3のベータ版を使ってみたんですが、文法定義スクリプトの仕様が一部変更になっていますね。

	StateAttribute_DefaultColor("DD8800")

等の部分を

	StateAttribute_DefaultColor(1)

等と指定し、Mode PreferencesメニューのColorsタブで具体的な色を指定することになります。
・2015年10月7日更新
 バージョン3からは正規表現が使えるようになっているので、全面的に書き直しました。ついでに、手控え用として、「H271007」のような表現で始まる段落と、「#」で始まる段落にも色をつけることにしました。

GlobalAttribute_SDFVersion("3.0")
GlobalAttribute_SDFName("kian")

state(idle)
{
	{regexp"^(1 )?[H|S|T|M][\\d|x]{6,6}",{ChangeState(ymd)}}
	{regexp"^#",{ChangeState(comment)}}
	{regexp"^第[0-9]+ ",{ChangeState(dai)}}
	{regexp"^第[0-9]+条",{ChangeState(dai)}}
	{regexp"^[0-9]+(\\(\\d+\\))* ",{ChangeState(suu)}}
	{regexp"^\\(\\d+\\)[ア-ン]* ",{ChangeState(kakkosuu)}}
	{regexp"^[ア-ン](\\([ア-ン]\\))* ",{ChangeState(kana)}}
	{regexp"^\\([ア-ン]\\)[a-z]* ",{ChangeState(kakkokana)}}
	{regexp"^[a-z] |\\([a-z]\\) |^[①-⑨]+ |^[α-ω] ",{ChangeState(sonota)}}
}

state(ymd)
{
	StateAttribute_ColorSlot(0)
	{lineend,{ChangeState(idle)}}
}

state(comment)
{
	StateAttribute_ColorSlot(7)
	{lineend,{ChangeState(idle)}}
}

state(dai)
{
	StateAttribute_ColorSlot(1)
	{lineend,{ChangeState(idle)}}
}

state(suu)
{
	StateAttribute_ColorSlot(2)
	{lineend,{ChangeState(idle)}}
}

state(kakkosuu)
{
	StateAttribute_ColorSlot(3)
	{lineend,{ChangeState(idle)}}
}

state(kana)
{
	StateAttribute_ColorSlot(4)
	{lineend,{ChangeState(idle)}}
}

state(kakkokana)
{
	StateAttribute_ColorSlot(5)
	{lineend,{ChangeState(idle)}}
}

state(sonota)
{
	StateAttribute_ColorSlot(6)
	{lineend,{ChangeState(idle)}}
}

更新履歴

・2015年10月25日更新
 「第n条」の処理を単純化しました。何が続こうがとにかく行頭に「第n条」(n≧0)と書いてあればそれ用の処理をするようにしました。
・2015年10月27日更新
 バージョン3のスクリプトにおいて、例えば、「2(1) 」を「2 」と同様の、「(3)ア 」を「(3) 」と同様の色になるようにしました。