青空文庫の注記文法
青空文庫では、テキスト中のルビや強調等に関する注記記法が定められています。
青空文庫の注記記法は入れ子になるため、反復補題により正規言語には属しません。
このページでは、青空文庫の注記記法を、解析表現文法 (Parsing Expression Grammar…PEG) で表記することを試みます。解析表現文法は、解析木が一意であり、また字句解析が不要のため分かりやすい等の特徴があります。
青空文庫の注記を分析文法で表現することで、テキスト入力時に注記規則を機械的にチェックでき、注記の間違いを減らすことができます。また青空文庫ビューア等の作成者にとっても、パーザ実装の簡略化の参考になる可能性があります。(実際に本文法を組み込むことで、パーザ部分のコード量を大幅に削減した青空文庫の文法チェック・HTML5変換ツールの実装がありますので興味のある方は参照ください。)
今後は、試作した文法を既存の青空文庫作品に対して適用・検証する予定です。文法エラーが起こる箇所については、テキストの間違いによると見られる場合は青空文庫の担当者に確認をお願いし、文法の誤りである場合は継続的に修正していく予定です。
なお、この文法を満たしていても青空文庫の記法に従っているとは限りません。たとえばJIS X 0208以外の漢字は使われていないか、または強調注記の引用が直前のテキストに一致するか、等は別途チェックする必要があります。
既存の青空文庫は新注記とは異なる注記で記述されているので、必ずしも下記の文法を満たすとは限りません。
文字の記法
青空文庫では、JIS X 0208に属する文字はそのまま記述しますが、それ以外の文字・漢字は、外字注記の記法を利用します。また、漢文・欧文なども特殊な記法を用います。
文字列 ← 文字 + 文字 ← ( !( "\n" ) !( "[#" ) !( "※[#" ) !( ( "〔" 欧文字 ) ) !( "《" ) !( "》" ) !( "|" ) .) / 漢字外字 / 非漢字外字 / 漢文 漢字 ← ( [ 㐀-鿋 豈-龎 𠀀- ] [ 󠄀-󠇯 ] ? ) / [ "仝〆○々" ] / 漢字外字 かな ← [ ぁ-ん ァ-ヶ ゛-ゞ ・-ヾ ] / "/″\" / "/\" 漢字外字 ← ( "※[#二の字点、1-2-22]" / ( "※[#「" 注記文字列 "]" ) / ( "※[#二の字点、" 注記文字列 "]" ) / ( "※[#濁点付き二の字点、" 注記文字列 "]" ) ) 非漢字外字 ← ( "※[#" !( "「" ) 注記文字列 "]" ) 漢文 ← ( ( 訓点送り ? 返り点 ) / 訓点送り ) 訓点送り ← "[#(" ( 漢字 / かな ) + ")]" 返り点 ← "[#" ( ( 返り順序点 返りレ点 ? ) / 返りレ点 ) "]" 返り順序点 ← [ "一二三四上中下天地人甲乙丙丁" ] 返りレ点 ← "レ" 欧文字 ← [ a-z A-Z α-ρ σ-ω Α-Ρ Σ-Ω А-я " Ёё" ]
文字修飾の記法
青空文庫では、文字の修飾の注記は以下の文法で記述します。
一般文字列 ← ( ( ( 文字列 / 欧文 ) 引用注記 * 一般ルビ ? 引用注記 * ) / ( 指定ルビ 引用注記 * ) ) + 注記文字列 ← ( !( "]" ) 文字 ) + 引用文字列 ← ( ( ( 引用文字 + / 欧文 ) 引用注記 * 一般ルビ ? 引用注記 * ) ) + 引用文字 ← ( !( "」は" ) !( "」の" ) !( "」に" ) !( "」]" ) 文字 ) + 引用注記 ← 修飾注記 / 原文注記 / 入力者注記 ルビ注記 ← ルビ修飾注記 / ルビ原文注記 / ルビ入力者注記 修飾注記 ← ( "[#「" 引用文字列 "」" 修飾指定 "]" ) ルビ修飾注記 ← ( "[#ルビの「" 引用文字列 "」" 修飾指定 "]" ) 原文注記 ← ( "[#「" 引用文字列 "」" "の左" ? "に「" 引用文字列 "」の注記]" ) ルビ原文注記 ← ( "[#ルビの「" 引用文字列 "」" "の左" ? "に「" 引用文字列 "」の注記]" ) 入力者注記 ← ( "[#「" 引用文字列 "」は" 底本注記 "]" ) ルビ入力者注記 ← ( "[#ルビの「" 引用文字列 "」は" 底本注記 "]" ) 底本注記 ← ( "底本では「" 引用文字列 "」" ) / "ママ" 修飾指定 ← ( "に" 強調 ) / ( "の" 左強調 ) / ( "の" 左ルビ ) / ( "は" 字体 ) / ( "は" 文字サイズ ) 強調 ← ( "二重" ? ( "傍線" / "波線" / "破線" / "鎖線" ) ) / "傍点" / "白ゴマ傍点" / "丸傍点" / "白丸傍点" / "×傍点" / "黒三角傍点" / "白三角傍点" / "二重丸傍点" / "蛇の目傍点" / "白四角傍点" 左強調 ← "左に" 強調 左ルビ ← "左に「" 引用文字列 "」のルビ" 字体 ← 見出し / 罫囲み / "太字" / "斜体" / "分数" / "上付き小文字" / "下付き小文字" / "篆書体" / "小書き" / "行右小書き" / "行左小書き" / "横組み" / "縦中横" / "合字" / "ローマ数字" 見出し ← ( "窓" / "同行" ) ? ( "大" / "中" / "小" ) "見出し" 罫囲み ← "二重" ? "罫囲み" 文字サイズ ← 数 "段階" ( "大きな" / "小さな" ) 数 ← ( [ 0-9 ] + / [ 0-9 ] + / [ "一二三四五六七八九十" ] ) 一般ルビ ← 一般ルビ2 ルビ注記 * 指定ルビ ← 指定ルビ2 ルビ注記 * 一般ルビ2 ← "《" 指定ルビ2 ← ( "|" ( 文字列 / 欧文 ) 引用注記 * "《" ) 欧文 ← ( "〔" 欧文字 ( 欧文字 / [ !-~ ] / 引用注記 ) + "〕" )
行の記法
青空文庫では、各行は以下の文法で記述します。
行 ← ( 一般注記 / 一般文字列 ) + 一般注記 ← 囲み注記 / 地上げ注記 / 図 囲み注記 ← ( "[#" ( ( "割り注" / 強調 / 左強調 / 字体 ) / 文字サイズ ) "]" ) 文字サイズ終 ← "大きな文字" / "小さな文字" 地上げ注記 ← ( 地寄り / 地付き / 地上げ ) 地寄り ← "[#下げて、地より" 数 "字あきで]" 地上げ ← "[#地から" 数 "字上げ]" 地付き ← "[#地付き]" 図 ← ( "[#" 図注記 ( "(" / "(" ) ファイル名 ".png" 図大きさ ? ( ")" / ")" ) "入る]" ) 図注記 ← ( !( "(" ) !( "(" ) 文字 ) + ファイル名 ← ( !( ".png" ) 文字 ) + 図大きさ ← "、横" 数 "×縦" 数
段落の記法
青空文庫では、全体の段落は以下の記法で記述します。
ブロック ← ( ページ指定 / 段落字下げ / 段落指定 / 段落 ) "[#本文終わり]" ? ブロック2 ← ページ指定 / 段落指定 / 段落 ブロック3 ← 段落字下げ / 段落指定 / 段落 段落 ← 字下げ ? 字下げ ← ( "[#" 数 "字下げ]" ) ページ指定 ← 左右中央 / 改まり注記 左右中央 ← "[#ページの左右中央]" "\n" ブロック3 * "[#改ページ]" "\n" 改まり注記 ← ( "[#改丁]" / "[#改ページ]" ) "\n" 段落指定 ← ( 段落字詰め / 段落地付き / 段落字上げ / 改段 / 段落字体 / 段落文字大 / 段落文字小 / 段組み ) "\n" 改段 ← "[#改段]" 段落字下げ ← 段落字下げ2 + 字下げ終 "\n" 段落字下げ2 ← ( ( 改行天付き / 天字下げ / 文字下げ / 文字下げ2 ) "\n" ブロック2 * ) 改行天付き ← "[#ここから改行天付き、折り返して" 数 "字下げ]" 天字下げ ← "[#天から" 数 "字下げ]" 文字下げ ← "[#ここから" 数 "字下げ]" 文字下げ2 ← "[#ここから" 数 "字下げ、折り返して" 数 "字下げ]" 字下げ終 ← "[#ここで字下げ終わり]" 段落字詰め ← ( "[#ここから" 数 "字詰め]\n" ブロック * ) 段落地付き ← ( "[#ここから地付き]\n" ブロック * "[#ここで地付き終わり]" ) 段落字上げ ← ( "[#ここから地から" 数 "字上げ]\n" ブロック * "[#ここで字上げ終わり]" ) 段落字体 ← ( "[#ここから" 字体 "]\n" ブロック * "[#ここで" 字体 "終わり]" ) 段落文字大 ← ( "[#ここから" 数 "段階大きな文字]\n" ブロック * "[#ここで大きな文字終わり]" ) 段落文字小 ← ( "[#ここから" 数 "段階小さな文字]\n" ブロック * "[#ここで小さな文字終わり]" ) 段組み ← ( "[#ここから" 数 "段組み" "、段間に罫" ? "]\n" ブロック * "[#ここで段組み終わり]" )
解析表現文法について
解析表現文法 (PEG) は、TransMoGrifier (1965), Top-Down Parsing Language (1972) 等の系譜に連なる最新の再帰下降型パーサ技術であり、2004年にBryan Ford氏によって開発されました。
例えばスクリプト言語でよく利用される「正規表現」は「正規言語」の解析プログラムの実装の大幅な簡略化に貢献しましたが、解析表現文法は、これと同様の効果をより複雑な文法に適用させることができます。
解析表現文法では、解析木は上位規則優先マッチで一意となります。そのため、優先度の低いマッチにより重要な規則があったとしても、隠蔽されるという問題がありました。これを解決するための研究がいくつか存在しています。