PerlでPukiWikiからMarkdownに半自動変換する

PukiWikiMarkdown移行の経緯

少し前になりますがバイト先でPukiWikiに溜めてきたノウハウをプリザンターというプラットフォームに移行することになりました。

しかしPukiWikiPukiWiki記法で書かれているのに対し、プリザンターはMarkdown記法。手動で直すにはあまりに膨大な量で、なんとか半自動で移行できないかと調べてたらこちらのワンライナーというものを発見。

qiita.com

Macのターミナルで実行できました。

基本構文は以下(wikiの文章はあらかじめtxtデータとして保存しておきます)

cat pukiwiki.txt | sed -e 's/ \[#[0-9a-z]\+\]$//g' -e 's/~$//g' | less > markdown.txt
  • cat:ファイルまたは標準入力の内容をそのまま標準出力に出力するコマンド。
  • |:通称パイプ。複数のコマンドをつなぎ、標準出力を次のコマンドに渡す。
  • sed:文字列を全置換したり、行単位で抽出したり、削除したり、いろいろなテキスト処理のできるコマンド。
  • -e:perlワンライナーとして利用する。その後ろに実行したいperlスクリプトを''で囲って指定。
  • less:入力の全部をターミナル上でスクロールしながら見る。catだとターミナル上を一瞬で流れてしまうので、最後の1画面分以外は見ることができない。
  • >:表示されている内容をファイルに書き込む。

ただし上のコマンドだと一部の拡張正規表現が使えません。 なので、以下のように変えます。

cat test.txt | perl -pe 's/ \[#[0-9a-z]+\]$//g; s/~$//g;' | less > markdown.txt
  • sedは文字列に特化したコマンドだが、perlならさらに複雑な処理も覚えればできる。
  • -p :perlsedっぽくするオプション。

コマンドの''内の読み方

上のコマンドで特に''で囲まれている部分は何やら訳のわからない文字列の集合に見えますが、以下の法則を元に作られています。

変換の基本構文

s/hogehoge/fugafuga/g;

という文があれば、hogehogeがfugafugaに変換されます。

正規表現

これに関してはいろんな方がまとめてくださっているので、そちらを参考にしてください!

userweb.mnet.ne.jp

メタ文字

上の正規表現で使われている記号(=メタ文字)は普通に書いただけでは検索対象として認識されません。

. ^ $ [ ] * + ? | ( )

を検索対象としたい場合は、以下のように表記します。

\. \^ \$ \[ \] \* \+ \? \| \( \)

\ 自体は、\と書きます。

なお、Windowsの場合は上の\は全て¥です。

実例から学ぶ

以下、実際に使った正規表現のコマンドをまとめておきます。

末尾のハッシュを削る

-e 's/ \[#[0-9a-z]+\]$//g'
  • []で囲むと、[]内のいずれかという意味になる。[0-9][a-z]を連続して書くとこうなる。
  • +は直前のパターンの1回以上繰り返し
  • 最後の$は文末であるという意味。

末尾の~を削る

-e 's/~$//g'

#で始まる文一括削除

-e 's/^#.*//g'
  • 最初の^は文頭であるという意味。
  • .は任意の一文字、*は直前のパターンの0回以上繰り返しという意味なので、.*で任意の文字列という意味。

太字を変換(''→**)

-e 's/\'\'/\*\*/g'
  • この時、コマンド全体を囲む'を"に変更すること!

見出しを# に変更(*→# )

-e 's/^\*\*\*/### /g' -e 's/^\*\*/## /g' -e 's/^\*/# /g'
  • 半角スペースはそのまま半角空ければOK

箇条書きを*に変更(-→* )

-e 's/^---/ \* /g' -e 's/^--/ \* /g' -e 's/^-/\* /g'

1.の箇条書き(+→1. 、++→ *)

-e 's/^+++/ \* /g' -e 's/^++/ \* /g' -e 's/^+/1\. /g'

サイズ表記を削除(&size(20){文字}→文字)

-e 's/&size\(\d+\)\{(.*)\}/$1/g'
  • 文字の部分をそのまま維持したい場合、その部分を()で囲む。この場合は(.*)の部分。変換後の正規表現では該当箇所を$1と表記する。

リンク表記を変換

-e 's/\[\[(.*)>http:\/\/(.*)\]\]/\[$1\]\(http:\/\/$2\)/g'
-e 's/\[\[(.*)>https:\/\/(.*)\]\]/\[$1\]\(https:\/\/$2\)/g'
  • サイズ表記の項と同様。複数の文字を維持する時は$1、$2…と使える。

参考