Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
#!/usr/bin/env perl
use strict;
use warnings;
use Pod::Usage;
use Text::Markdown 'markdown';
use HTML::TreeBuilder;
use List::Util 'max';
# デフォルトのリストスタイル
# disc: 黒丸
# square: 四角
# circle: 白丸
# alpha: アルファベット
use constant DEFAULT_LIST => 'disc';
# リストの文字数上限
# WEB+DB PRESSの場合、リストは、1行63桁(文字)まで
# 書籍の場合、リストは1行69桁(文字)まで
use constant MAX_LIST_LENGTH => 69;
# 本文埋め込みリストの文字数上限
# WEB+DB PRESSの場合、本文リストは1行55桁(文字)まで
# 書籍の場合、本文リストは1行73桁(文字)まで
use constant MAX_INLINE_LIST_LENGTH => 73;
# 本文中に(◯1)や(1)など、リストを参照するときの形式に変換する
# 「リスト1.1(c1)を見てください」
# ->
# 「リスト1.1(◯1)を見てください」となる
#
# (d1) -> (1) # desc
# (c1) -> (◯1) # circle
# (s1) -> [1] # square
# (a1) -> (a) # alpha
#
# エスケープも可能
# (\d1) -> (d1)
# (\c1) -> (c1)
sub to_list_style {
my $text = shift;
# convert
$text =~ s/\(d(\d+)\)/$1/g;
$text =~ s/\(c(\d+)\)/(○$1/g;
$text =~ s/\(s(\d+)\)/$1/g;
$text =~ s/\(a(\d+)\)/'(' . chr($1 + 96) . ')'/ge;
# escape
$text =~ s/\(\\([dcsa]?\d+)\)/($1)/g;
return $text;
}
sub to_inao {
my $text = shift;
my $html = markdown($text);
my $tree = HTML::TreeBuilder->new;
$tree->no_space_compacting(1);
$tree->parse_content(\$html);
my $inao = q[];
my $body = $tree->find('body');
for my $elem ($body->content_list) {
if ($elem->tag =~ /^h(\d+)/) {
my $level = $1;
$inao .= '' x $level;
$inao .= $elem->as_trimmed_text;
$inao .= "\n";
}
elsif ($elem->tag eq 'p') {
my $p = q[];
for my $inline ($elem->content_list) {
if (ref $inline eq '') {
# (注:)は脚注としてあつかう
$inline =~ s!\(注:(.+?)\)!◆注/◆$1◆/注◆!gs;
# 改行を取り除く
$inline =~ s/(\n|\r)//g;
# キャプション
if ($inline =~ s!^●(.+?)::(.+)!$1\t$2!) {
$inline =~ s!\[(.+)\]$!\n$1!;
}
# リストスタイル文字の変換
$inline = to_list_style($inline);
$p .= $inline;
}
elsif ($inline->tag eq 'code') {
$p .= '◆cmd/◆';
$p .= $inline->as_trimmed_text;
$p .= '◆/cmd◆';
}
elsif ($inline->tag eq 'strong') {
$p .= '◆b/◆';
$p .= $inline->as_trimmed_text;
$p .= '◆/b◆';
}
elsif ($inline->tag eq 'em') {
$p .= '◆i/◆';
$p .= $inline->as_trimmed_text;
$p .= '◆/i◆';
}
elsif ($inline->tag eq 'kbd') {
$p .= $inline->as_trimmed_text;
$p .= '';
}
elsif ($inline->tag eq 'span') {
my $class = $inline->attr('class');
# 赤字
# <span class='red'>赤字</span>
if ($class eq 'red') {
$p .= '◆red/◆';
$p .= $inline->as_trimmed_text;
$p .= '◆/red◆';
}
# ruby
# <span class='ruby'>漢字(かんじ)</span>
elsif ($class eq 'ruby') {
my $ruby = $inline->as_trimmed_text;
$ruby =~ s!(.+)\((.+)\)!◆ルビ/◆$1$2◆/ルビ◆!;
$p .= $ruby;
}
# その他の記号
# <span class='symbol'>=></span>
elsif ($class eq 'symbol') {
$p .= '';
$p .= $inline->as_trimmed_text;
$p .= '';
}
}
}
if ($p !~ /^[\s ]+$/) {
$inao .= "$p\n";
}
}
elsif ($elem->tag eq 'pre') {
my $code = $elem->find('code');
my $text = '';
if (defined($code)) {
$text = $code->as_text;
}
my $list_label = 'list';
my $comment_label = 'comment';
# キャプション
$text =~ s!●(.+?)::(.+)!$1\t$2!g;
# 「!!! cmd」で始まるコードブロックはコマンドライン(黒背景)
if ($text =~ /!!!(\s+)?cmd/) {
$text =~ s/.+?\n//;
$list_label .= '-white';
$comment_label .= '-white';
}
# リストスタイル
$text = to_list_style($text);
# asciiのみカウント。日本語は目視でがんばる
my $max = max map { length } grep /^[\x00-\x7f]*$/, split /\r?\n/, $text;
if (defined($max)) {
if ($text =~ /^●/) {
if ($max > MAX_LIST_LENGTH) {
warn "リストは" . MAX_LIST_LENGTH . "文字まで!(現在$max使用):\n$text\n\n";
}
}
else {
if ($max > MAX_INLINE_LIST_LENGTH) {
warn "本文埋め込みリストは" . MAX_INLINE_LIST_LENGTH . "文字まで!(現在$max使用):\n$text\n\n";
}
}
} else {
warn 'リスト中の文字列に日本語が入っており、最大文字数を正しく計算できませんでした。 See: ' .$0. ':'. $= . "\n";
warn '-' x 72 . "\n";
warn $text;
warn '-' x 72 . "\n";
warn "\n";
}
# コード内コメント
$text =~ s!\(注:(.+?)\)!$comment_label/◆$1◆/$comment_label!gs;
# コード内強調
$text =~ s!\*\*(.+?)\*\*!◆cmd-b/◆$1◆/cmd-b◆!gs;
$inao .= "$list_label/◆\n";
$inao .= $text;
$inao .= "◆/$list_label\n";
}
elsif ($elem->tag eq 'ul') {
for my $list ($elem->find('li')) {
$inao .= '' . to_list_style($list->as_trimmed_text) . "\n";
}
}
elsif ($elem->tag eq 'ol') {
my $list_style = $elem->attr('class') || DEFAULT_LIST;
my $s = substr $list_style, 0, 1;
my $i = 0;
for my $list ($elem->find('li')) {
$inao .= to_list_style(
sprintf('(%s%d)%s', $s, ++$i, $list->as_trimmed_text)) . "\n";
}
}
elsif ($elem->tag eq 'table') {
my $summary = $elem->attr('summary') || '';
$summary =~ s!(.+?)::(.+)!$1\t$2\n!;
$inao .= "◆table/◆\n";
$inao .= $summary;
$inao .= "◆table-title◆";
for my $table ($elem->find('tr')) {
for my $item ($table->find('th')){
$inao .= $item->as_trimmed_text;
$inao .= "\t";
}
for my $item ($table->find('td')){
$inao .= $item->as_trimmed_text;
$inao .= "\t";
}
chop($inao);
$inao .= "\n"
}
$inao .= "◆/table◆\n";
}
elsif ($elem->tag eq 'div' and $elem->attr('class') eq 'column') {
$inao .= "◆column/◆\n";
$inao .= to_inao($elem->as_text);
$inao .= "◆/column◆\n";
}
elsif ($elem->tag eq 'blockquote') {
my $blockquote = $elem->as_trimmed_text;
$blockquote =~ s/(\s)//g;
$inao .= "◆quote/◆\n";
$inao .= $blockquote;
$inao .= "\n◆/quote◆\n";
}
}
return $inao;
}
my $infile = $ARGV[0]
or pod2usage(-1);
open my $fh, '<', $infile or die $!;
my $text = do { local $/; <$fh> };
close $fh;
print to_inao($text);
__END__
=head1 NAME
markdown2inao.pl - markdown to inao converter
=head1 SYNOPSIS
markdown2inao.pl input.markdown.txt
=cut
# 見出し1(大見出し、節)
## 見出し2(中見出し、項)
### 見出し3(小見出し、目)
 段落冒頭の字下げは、このように手動でお願いします。
改行は、(改行)
このように自動で取り除かれます。
 通常の本文**強調(ボールド)**通常の本文_斜体(イタリック)_通常の本文`インラインのコード`通常の本文(注:注釈ですよ。)通常の本文<kbd>Enter</kbd>(←キーボードフォント)<span class='red'>赤文字</span>通常の本文<span class='ruby'>外村(ほかむら)</span>(←ルビ)。
> 引用です引用です引用です引用です引用です引用です引用です引用です
> 引用です引用です引用です引用です引用です引用です引用です引用です
> 引用です引用です引用です引用です引用です引用です引用です引用です
> 引用です引用です引用です引用です引用です引用です引用です引用です
<div class='column'>
#### コラム見出し
 コラム本文コラム本文コラム本文コラム本文コラム本文コラム本文コラム本文コラム本文コラム本文コラム本文コラム。
##### コラム小見出し
 コラム内でも**強調**などが使えます。
</div>
## 箇条書き(リスト)いろいろ
### 通常の箇条書き
* 通常の箇条書き
* 通常の箇条書き
* 通常の箇条書き
* 通常の箇条書き
* 通常の箇条書き
### 連番箇条書き(黒丸数字)
1. 連番箇条書き(黒丸数字)
2. 連番箇条書き(黒丸数字)
3. 連番箇条書き(黒丸数字)
4. 連番箇条書き(黒丸数字)
5. 連番箇条書き(黒丸数字)
### 連番箇条書き(白丸数字)
<ol class='circle'>
<li>連番箇条書き(白丸数字)</li>
<li>連番箇条書き(白丸数字)</li>
<li>連番箇条書き(白丸数字)</li>
<li>連番箇条書き(白丸数字)</li>
<li>連番箇条書き(白丸数字)</li>
</ol>
### 連番箇条書き(黒四角数字)
<ol class='square'>
<li>連番箇条書き(黒四角数字)</li>
<li>連番箇条書き(黒四角数字)</li>
<li>連番箇条書き(黒四角数字)</li>
<li>連番箇条書き(黒四角数字)</li>
<li>連番箇条書き(黒四角数字)</li>
</ol>
### 連番箇条書き(アルファベット)
<ol class='alpha'>
<li>連番箇条書き(アルファベット)</li>
<li>連番箇条書き(アルファベット)</li>
<li>連番箇条書き(アルファベット)</li>
<li>連番箇条書き(アルファベット)</li>
<li>連番箇条書き(アルファベット)</li>
</ol>
 本文から参照するときは(d1)、(d2)、(c1)、(c2)、(s1)、(s2)、(a1)、(a2)のようにします。
<ol class='square'>
<li>hogehogeをします</li>
<li>fugafugaと(s1)の結果を足し合わせます</li>
</ol>
●リスト1.1 キャプション(コードのタイトル)
function hoge() {
alert(foo); … (c1)
alert(bar); … (c2)
alert(\c1); // \でエスケープできます
}
 リスト1.1(c1)ではアラートを出しています。(c2)でもアラートを出しています。(\a1)エスケープできます。
## ソースコード
### 本文埋め込みコード
 本文中で流れでコードを掲載するときに使用します。
function **foo**(a) { // コード内強調
alert(a); (注:こんな風にコメントがつけられます)
}
(注:見出し的にも使えます)
function bar(b) {
alert(b);
}
 このように、上下に本文が入ります。
 本文から一連の流れで読んでもらうことができますが、コードがページをまたぐ可能性がございます。
### リスト(名前付きのコード)★要キャプション★
 リストは、本文とは別ボックス(別なパーツ)として紙面の端に寄せてレイアウトしますので、コードがページをまたぐことはございません(1ページを超えるコードはまたぎますけど)。
 以下、このリストや後述する図や表など、別ボックスものの場合のご注意点です。
* キャプション(タイトル)が必須です
* 「**リスト1.1**をご覧ください」「○○のコードを示します(**リスト1.1**)」「○○を**表1.1**にまとめました」みたいな感じで、本文から番号で参照してください
* 初出時のみ**リスト1.1**のように太字にします(2度目以降は通常の本文です)
(このドキュメントでは、別ボックスものは見出しに★要キャプション★と書いています)
●リスト1.1::キャプション(コードのタイトル)
function **foo**(a) { // コード内強調
alert(a); (注:こんな風にコメントがつけられます)
}
(注:見出し的にも使えます)
function bar(b) {
alert(b);
}
## コマンドの実行結果
 コマンドは、「!!! cmd」と付けていただく必要があるだけで、基本的には上記ソースコードと同じです。
 ただし、呼称が「リスト」ではなく「図」となります。また、コマンド行の行頭にはプロンプトを付けてください。
### 本文埋め込みコマンド
!!! cmd
$ command **foo** // コマンド内強調
bar (注:こんな風にコメントがつけられます)
(注:見出し的にも使えます)
function bar(b) {
alert(b);
}
### 図(名前付きのコマンド)★要キャプション★
!!! cmd
●図1.1::キャプション(コマンドのタイトル)
$ command **foo** // コマンド内強調
bar (注:こんな風にコメントがつけられます)
(注:見出し的にも使えます)
function bar(b) {
alert(b);
}
## 図★要キャプション★
 スクリーンショットなど、別ファイルを参照する図です。
●図1.1::キャプション(図のタイトル)[figure/sample.png]
## 表★要キャプション★
<table summary='表1.1::キャプション(表のタイトル)'>
<tr>
<th>表タイトル1</th>
<th>表タイトル2</th>
</tr>
<tr>
<td>内容1</td>
<td>内容2</td>
</tr>
<tr>
<td>内容1</td>
<td>内容2</td>
</tr>
</table>
## その他の記号
<span class='symbol'>→</span><span class='symbol'>←</span><span class='symbol'>↑</span><span class='symbol'>↓</span>
<span class='symbol'>←→</span>
<span class='symbol'>>=</span><span class='symbol'>=></span>
## キーボードフォント
<kbd>A</kbd>~<kbd>Z</kbd>
<kbd>a</kbd>~<kbd>z</kbd>
<kbd>0</kbd>~<kbd>9</kbd>
<kbd>F1</kbd>~<kbd>F12</kbd>
<kbd>→</kbd><kbd>↓</kbd><kbd>↑</kbd><kbd>←</kbd>
<kbd>End</kbd>
<kbd>Alt</kbd>
<kbd>Ctrl</kbd><kbd>Control</kbd>
<kbd>Shift</kbd>
<kbd>Tab</kbd>
<kbd>Esc</kbd>
<kbd>Delete</kbd>
<kbd>Insert</kbd>
<kbd>Pause</kbd>
<kbd>Break</kbd>
<kbd>Home</kbd>
<kbd>Back Space</kbd>
<kbd>Space</kbd>
<kbd>Pgup</kbd><kbd>Pgdn</kbd>
<kbd>Enter</kbd>
<kbd>!</kbd>
<kbd>#</kbd>
<kbd>$</kbd>
<kbd>%</kbd>
<kbd>&</kbd>
<kbd>'</kbd>
<kbd>(</kbd><kbd>)</kbd>
<kbd>[</kbd><kbd>]</kbd>
<kbd>=</kbd>
<kbd>-</kbd>
<kbd>^</kbd>
<kbd>~</kbd>
<kbd>|</kbd>
<kbd>+</kbd>
<kbd>*</kbd>
<kbd>;</kbd>
<kbd>:</kbd>
<kbd>,</kbd>
<kbd>.</kbd>
<kbd>/</kbd>
<kbd>?</kbd>
<kbd>_</kbd>
<kbd>@</kbd>
<kbd>`</kbd>
<kbd>"</kbd>
■見出し1(大見出し、節)
■■見出し2(中見出し、項)
■■■見出し3(小見出し、目)
 段落冒頭の字下げは、このように手動でお願いします。改行は、(改行)このように自動で取り除かれます。
 通常の本文◆b/◆強調(ボールド)◆/b◆通常の本文◆i/◆斜体(イタリック)◆/i◆通常の本文◆cmd/◆インラインのコード◆/cmd◆通常の本文◆注/◆注釈ですよ。◆/注◆通常の本文Enter▲(←キーボードフォント)◆red/◆赤文字◆/red◆通常の本文◆ルビ/◆外村◆ほかむら◆/ルビ◆(←ルビ)。
◆quote/◆
引用です引用です引用です引用です引用です引用です引用です引用です引用です引用です引用です引用です引用です引用です引用です引用です引用です引用です引用です引用です引用です引用です引用です引用です引用です引用です引用です引用です引用です引用です引用です引用です
◆/quote◆
◆column/◆
■■■■コラム見出し
 コラム本文コラム本文コラム本文コラム本文コラム本文コラム本文コラム本文コラム本文コラム本文コラム本文コラム。
■■■■■コラム小見出し
 コラム内でも◆b/◆強調◆/b◆などが使えます。
◆/column◆
■■箇条書き(リスト)いろいろ
■■■通常の箇条書き
・通常の箇条書き
・通常の箇条書き
・通常の箇条書き
・通常の箇条書き
・通常の箇条書き
■■■連番箇条書き(黒丸数字)
(1)連番箇条書き(黒丸数字)
(2)連番箇条書き(黒丸数字)
(3)連番箇条書き(黒丸数字)
(4)連番箇条書き(黒丸数字)
(5)連番箇条書き(黒丸数字)
■■■連番箇条書き(白丸数字)
(○1)連番箇条書き(白丸数字)
(○2)連番箇条書き(白丸数字)
(○3)連番箇条書き(白丸数字)
(○4)連番箇条書き(白丸数字)
(○5)連番箇条書き(白丸数字)
■■■連番箇条書き(黒四角数字)
[1]連番箇条書き(黒四角数字)
[2]連番箇条書き(黒四角数字)
[3]連番箇条書き(黒四角数字)
[4]連番箇条書き(黒四角数字)
[5]連番箇条書き(黒四角数字)
■■■連番箇条書き(アルファベット)
(a)連番箇条書き(アルファベット)
(b)連番箇条書き(アルファベット)
(c)連番箇条書き(アルファベット)
(d)連番箇条書き(アルファベット)
(e)連番箇条書き(アルファベット)
 本文から参照するときは(1)、(2)、(○1)、(○2)、[1]、[2]、(a)、(b)のようにします。
[1]hogehogeをします
[2]fugafugaと[1]の結果を足し合わせます
◆list/◆
●リスト1.1 キャプション(コードのタイトル)
function hoge() {
alert(foo); … (○1)
alert(bar); … (○2)
alert(c1); // \でエスケープできます
}
◆/list◆
 リスト1.1(○1)ではアラートを出しています。(○2)でもアラートを出しています。(a1)エスケープできます。
■■ソースコード
■■■本文埋め込みコード
 本文中で流れでコードを掲載するときに使用します。
◆list/◆
function ◆cmd-b/◆foo◆/cmd-b◆(a) { // コード内強調
alert(a); ◆comment/◆こんな風にコメントがつけられます◆/comment◆
}
◆comment/◆見出し的にも使えます◆/comment◆
function bar(b) {
alert(b);
}
◆/list◆
 このように、上下に本文が入ります。
 本文から一連の流れで読んでもらうことができますが、コードがページをまたぐ可能性がございます。
■■■リスト(名前付きのコード)★要キャプション★
 リストは、本文とは別ボックス(別なパーツ)として紙面の端に寄せてレイアウトしますので、コードがページをまたぐことはございません(1ページを超えるコードはまたぎますけど)。
 以下、このリストや後述する図や表など、別ボックスものの場合のご注意点です。
・キャプション(タイトル)が必須です
・「リスト1.1をご覧ください」「○○のコードを示します(リスト1.1)」「○○を表1.1にまとめました」みたいな感じで、本文から番号で参照してください
・初出時のみリスト1.1のように太字にします(2度目以降は通常の本文です)
(このドキュメントでは、別ボックスものは見出しに★要キャプション★と書いています)
◆list/◆
●リスト1.1 キャプション(コードのタイトル)
function ◆cmd-b/◆foo◆/cmd-b◆(a) { // コード内強調
alert(a); ◆comment/◆こんな風にコメントがつけられます◆/comment◆
}
◆comment/◆見出し的にも使えます◆/comment◆
function bar(b) {
alert(b);
}
◆/list◆
■■コマンドの実行結果
 コマンドは、「!!! cmd」と付けていただく必要があるだけで、基本的には上記ソースコードと同じです。
 ただし、呼称が「リスト」ではなく「図」となります。また、コマンド行の行頭にはプロンプトを付けてください。
■■■本文埋め込みコマンド
◆list-white/◆
$ command ◆cmd-b/◆foo◆/cmd-b◆ // コマンド内強調
bar ◆comment-white/◆こんな風にコメントがつけられます◆/comment-white◆
◆comment-white/◆見出し的にも使えます◆/comment-white◆
function bar(b) {
alert(b);
}
◆/list-white◆
■■■図(名前付きのコマンド)★要キャプション★
◆list-white/◆
●図1.1 キャプション(コマンドのタイトル)
$ command ◆cmd-b/◆foo◆/cmd-b◆ // コマンド内強調
bar ◆comment-white/◆こんな風にコメントがつけられます◆/comment-white◆
◆comment-white/◆見出し的にも使えます◆/comment-white◆
function bar(b) {
alert(b);
}
◆/list-white◆
■■図★要キャプション★
 スクリーンショットなど、別ファイルを参照する図です。
●図1.1 キャプション(図のタイトル)
figure/sample.png
■■表★要キャプション★
◆table/◆
●表1.1 キャプション(表のタイトル)
◆table-title◆表タイトル1 表タイトル2
内容1 内容2
内容1 内容2
◆/table◆
■■その他の記号
◆→◆◆←◆◆↑◆◆↓◆
◆←→◆
◆>=◆◆=>◆
■■キーボードフォント
A▲~Z▲
a▲~z▲
0▲~9▲
F1▲~F12▲
→▲↓▲↑▲←▲
End▲
Alt▲
Ctrl▲Control▲
Shift▲
Tab▲
Esc▲
Delete▲
Insert▲
Pause▲
Break▲
Home▲
Back Space▲
Space▲
Pgup▲Pgdn▲
Enter▲
!▲
#▲
$▲
%▲
&▲
'▲
(▲)▲
[▲]▲
=▲
-▲
^▲
~▲
|▲
+▲
*▲
;▲
:▲
,▲
.▲
/▲
?▲
_▲
@▲
`▲
"▲
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.