読者です 読者をやめる 読者になる 読者になる

ochalog

Ruby と MediaWiki が好きな電子・情報系の学生のブログ。

flex の練習:Hiki の見出し抽出

flex の練習その 2。昔 Hiki2MediaWiki でやったような Hiki の見出し抽出。

  • Hiki ソースを標準入力から読み込み、見出しのみを抽出して標準出力に出力する。
  • MediaWiki のように見出し番号を表示する。
  • 見出しレベルが連続していなくても、親子関係を正しく認識する。

hiki-outliner.l

/*
 * Hiki の見出し抽出
 * MediaWiki のように見出し番号をつけて表示する
 */
%{
  int n_bang_stack[7] = {0};
  int n_bang_stack_pos = 0;
  int heading_counter[7] = {0};

  // 見出しを表示する
  void print_heading(int* counter, const char* content);
%}

HEADING ^!{1,6}.+

%option main

%%

{HEADING} {
  int n_bang = 0;
  char* text_ptr = yytext;

  // '!' の数を調べる
  while (n_bang < 6 && *text_ptr == '!') {
    ++n_bang;
    ++text_ptr;
  }

  if (n_bang > n_bang_stack[n_bang_stack_pos]) {
    // 小見出しなので push する
    ++n_bang_stack_pos;
  } else {
    // 同レベルの見出しが見つかるまで pop する
    while (n_bang <= n_bang_stack[n_bang_stack_pos - 1]) {
      --n_bang_stack_pos;

      // 1 つ下のレベルの見出し番号をリセットする
      heading_counter[n_bang_stack_pos] = 0;
    }
  }

  n_bang_stack[n_bang_stack_pos] = n_bang;
  ++heading_counter[n_bang_stack_pos - 1];

  print_heading(heading_counter, text_ptr);
}

.  { }
\n { }

%%

void print_heading(int* counter, const char* content) {
  int i;

  putchar('0' + counter[0]);
  for (i = 1; i < 6 && counter[i] > 0; ++i) {
    putchar('.');
    putchar('0' + counter[i]);
  }
  putchar(' ');

  puts(content);
}

入力例 1

見出しレベルが連続している例。スパロボ Wikiサイバスター」より。

hiki-outliner-sample1-in.txt

!サイバスター
地球内部にひろがる異相世界ラ・ギアスに広大な版図をもつ「神聖ラングラン王国」で作られた風系魔装機。

!!サイバスター・ポゼッション
風の精霊王サイフィスと完全な同調を果たしたサイバスターの姿。

!登場作品と操縦者
基本的にマサキ・アンドー専用機として登場する。

バンプレストオリジナルロボットの元祖。

!!旧シリーズ

!!!第2次スーパーロボット大戦
初登場。

!!αシリーズ

!!!スーパーロボット大戦α
バランス調整で「サイフラッシュ」に加え「コスモノヴァ」を故障で使用不可という状態で参戦する。

!!!スーパーロボット大戦α外伝
マサキより遅れてセニアが地上に運び込み、次のマップからマサキがジャオームから乗り換える。

!装備・機能
高い運動性を誇り、機体とパイロットの回避力を高めれば避けて当てるリアルロボット的な運用法ができる。

入力例 2

見出しレベルが連続していない例。

hiki-outliner-sample2-in.txt

!サイバスター
地球内部にひろがる異相世界ラ・ギアスに広大な版図をもつ「神聖ラングラン王国」で作られた風系魔装機。

!!!サイバスター・ポゼッション
風の精霊王サイフィスと完全な同調を果たしたサイバスターの姿。

!登場作品と操縦者
基本的にマサキ・アンドー専用機として登場する。

バンプレストオリジナルロボットの元祖。

!!!旧シリーズ

!!!!第2次スーパーロボット大戦
初登場。

!!αシリーズ

!!!!スーパーロボット大戦α
バランス調整で「サイフラッシュ」に加え「コスモノヴァ」を故障で使用不可という状態で参戦する。

!!!!スーパーロボット大戦α外伝
マサキより遅れてセニアが地上に運び込み、次のマップからマサキがジャオームから乗り換える。

!装備・機能
高い運動性を誇り、機体とパイロットの回避力を高めれば避けて当てるリアルロボット的な運用法ができる。

出力例

./hiki-outliner < hiki-outliner-sample1-in.txt
./hiki-outliner < hiki-outliner-sample2-in.txt

どちらの例でも、以下のように正しい親子関係で MediaWiki の目次っぽく出力される。

1 サイバスター
1.1 サイバスター・ポゼッション
2 登場作品と操縦者
2.1 旧シリーズ
2.1.1 第2次スーパーロボット大戦
2.2 αシリーズ
2.2.1 スーパーロボット大戦α
2.2.2 スーパーロボット大戦α外伝
3 装備・機能