kibela2esa

正規表現

2019-02-07

表参道.rb #43

うなすけ

自己紹介

kibela2esa

kibelaの記事をesaに移行するscript

gemではない

kibela2esaにおける正規表現

TEAM='unasuke'
TITLE_PATTERN = %r[\A.*/kibela-#{TEAM}-\d+/(?<kind>wikis|blogs)/(?<path>[[:print:]]*/)*(?<id>\d)+-(?<name>[[:print:]]*)\.md\z]
ATTACHMENT_PATTERN = %r[^(?~http)(\.\./)*attachments/(?<attachment_name>\d+\.(png|JPG|jpg|jpeg|gif|PNG))]
kibela.rb#L6-L7

ナニコレ???

kibela2esaにおける正規表現

みやすく改行してみましょう

TEAM='unasuke'
TITLE_PATTERN = %r[\A.*
	/kibela-#{TEAM}-\d+
	/(?<kind>wikis|blogs)
	/(?<path>[[:print:]]*/)*
	(?<id>\d)+-(?<name>[[:print:]]*)\.md\z]x
ATTACHMENT_PATTERN = %r[^(?~http)
	(\.\./)*attachments/
	(?<attachment_name>\d+\.
		(png|JPG|jpg|jpeg|gif|PNG))
	]x
雑に改行を入れましたが、これも正しい正規表現です

正規表現の説明の前に

kibelaのexportされたデータを見てみましょう

正規表現の説明の前に

kibelaのexportされたデータ

正規表現の説明の前に

kibelaのexportされたデータ

  • kibela-unasuke-0/attachments/3.png
  • kibela-unasuke-0/wikis/2019/01/18/1-some.md
  • kibela-unasuke-0/wikis/other/dir/2-hogehoge.md
  • kibela-unasuke-0/blogs/unasuke/3-my_memo.md

kibelaのexportされたデータ

一般化してみましょう

  • kibela-unasuke-*/attachments/*.png
  • kibela-unasuke-*/wikis/**/1-some.md
  • kibela-unasuke-*/wikis/**/2-hogehoge.md
  • kibela-unasuke-*/blogs/**/3-my_memo.md

kibelaのexportされたデータ

一般化してみましょう 2

  • kibela-unasuke-*/attachments/*.png
  • kibela-unasuke-*/wikis/**/*-*.md
  • kibela-unasuke-*/wikis/**/*-*.md
  • kibela-unasuke-*/blogs/**/*-*.md


あーなんとなくわかってきた

exportされたデータの構造

記事 (blogs, wikis)

  1. kibela-(team)-(数字)/ がトップ
  2. blogs/ もしくは wikis/が続く
  3. (投稿者)/(番号)-(タイトル).md (blogの場合)
  4. (カテゴリ)/(階層)/(番号)-(タイトル).md (wikiの場合)

じゃあこれを正規表現にしていきましょう

exportされたデータの構造

記事 (blogs, wikis) の正規表現

TITLE_PATTERN = %r[
\A.* # 先頭に任意の文字列を許容
  /kibela-#{TEAM}-\d+ # /kibela-team名-数値 にマッチ
  /(wikis|blogs)      # /wikis か /blogs にマッチ
  /([[:print:]]*/)*   # /任意の文字列 の0回以上の連続にマッチ
  (\d)+-([[:print:]]*)\.md # 数値-任意の文字列.md にマッチ
  \z # 文字列の末尾
]x

正規表現はできた……

ので、マッチした部分を取り出したい

正規表現のキャプチャ

丸括弧 ( ) によってキャプチャをすることができます。
1,2,... ではなく、名前を付けることができます。 (?<name>pat)もしくは(?'name'pat)と記述します。
https://docs.ruby-lang.org/ja/latest/doc/spec=2fregexp.html

記事 (blogs, wikis) の正規表現

正規表現のキャプチャ

TITLE_PATTERN = %r[\A.*
	/kibela-#{TEAM}-\d+
	/(?<kind>wikis|blogs)
	/(?<path>[[:print:]]*/)*
	(?<id>\d)+-(?<name>[[:print:]]*)\.md\z]x
regexp = TITLE_PATTERN.match(filepath)
regexp[:kind] # これでblogsなのかwikisなのかわかる
regexp[:path] # これで記事のカテゴリがわかる
regexp[:name] # これで記事の名前が取れる

第一関門突破🎉🎉

第二関門😨

ATTACHMENT_PATTERN = %r[^(?~http)
  (\.\./)*attachments/
  (?<attachment_name>\d+\.
    (png|JPG|jpg|jpeg|gif|PNG))
  ]x

kibelaの記事に貼られた画像

<img
 title='foo'
 src='../../../../attachments/6.png' # この'6.png'が欲しい
 width="662"
 data-meta='{"width":662,"height":195}'>

ちなみにこれはmarkdown内に書かれています

kibelaの記事に貼られた画像

srcの中を取得したい

kibelaの記事に貼られた画像

以下の条件を満たす場合のみ

  • full URLでなく相対path
  • 階層は任意の深さ
  • attachments/数字.拡張子 で終わる

kibelaの記事に貼られた画像

以下の条件を満たす場合のみ

  • full URLでなく相対path ← 地味にキツい
  • 階層は任意の深さ ← わかる
  • attachments/数字.拡張子 で終わる ← 楽勝

非包含演算子

(?~式) という記法で、式にマッチする文字列を含まない任意の文字列にマッチします。
https://docs.ruby-lang.org/ja/latest/doc/spec=2fregexp.html

最高!!

非包含演算子について



言語標準でこの機能が使えるのはRubyだけ?

exportされたデータの構造

画像名の正規表現

ATTACHMENT_PATTERN = %r[
  ^ # 文字列の先頭
  (?~http) # http で開始しない
  (\.\./)*attachments/ # 任意の階層/attachmentsにマッチ
	(?<attachment_name>\d+ # 画像名(数字)
  \.(png|JPG|jpg|jpeg|gif|PNG)) # 画像名(拡張子)
	]x

まとめ

  • 非包含演算子は便利
    • Rubyで書いてよかった
  • 正規表現は便利
    • 容易に読みにくくできるので注意
  • HolyGrail/kibela2esaにstarお願いします