はてなダイアリーのインポートで移行した記事ですが、id記法で記述したはてなダイアリーへのリンクが全滅しています。これははてなダイアリーとはてなブログではid記法の仕様が異なるせいです。なんでうまいこと変換してくれないかなーと思いつつ一括で修正してみました。
例によって HatenaBlogWriter (hbw) を使うのが前提です。
はてなダイアリーとはてなブログでのid記法の違い
詳しくは今村さんのブログエントリを参照してください。
ここには書かれてなかったと思うのですが、もう一つ違いがあります。
はてなダイアリーでは a タグの href 属性値にid記法を書くとURLに展開してくれるのですが、はてなブログでは展開してくれません。はてなブログで有効な d:id:rna:20190128:p1 のようなid記法で書いてもダメです。
idリンクの置換
以下のようなスクリプトを書きました。要は正規表現置換なのですが、正規表現は苦手科目です… 何度も試行錯誤できるように元のエントリファイルをサブディレクトリにコピーして、それを入力として変換するようにしました。
convert-id-links.rb:
#!/usr/bin/env ruby # coding: utf-8 # HatenaBlogWriter のワーキングディレクトリで実行します。 # orig ディレクトリに変換前のエントリファイルをコピーしてから実行します。 ORIG_DIR = "orig" TB_SECTION_SEPARATOR = '<!-- trackback -->' def load_entry_file(filename) header = [] body = [] tb = [] File.open(filename) { |file| in_header = true in_tb = false file.each_line(chomp: true) { |line| if (line == TB_SECTION_SEPARATOR) then in_tb = true next elsif in_header && /^$/.match(line) then in_header = false next end if in_header then header.push(line) elsif in_tb then tb.push(line) else body.push(line) end } } return { :header => header, :body => body, :tb => tb } end def dump_entry_file(filename, entry) File.open(filename, "w") { |f| f.puts entry[:header] f.puts "" f.puts entry[:body] unless entry[:tb].empty? then f.puts TB_SECTION_SEPARATOR f.puts entry[:tb] end } end def convert_id_links(lines) in_super_pre = false new_lines = [] lines.each { |line| if in_super_pre then new_lines.push(line) in_super_pre = false if line.match(/^||<$/) next end if !in_super_pre && line.match(/^>\|\w*\|$/) then new_lines.push(line) in_super_pre = true next end # id link new_line = line.gsub(/((\[\])|(href=['"]\[?)|[^:]|^)(id:([\w-]+):(\d{8})(:[\w]+|#[\w]+)?)(\[\])?/i) { |matched| pre, esc_begin, href, link, id, date, sect, esc_end = $~.captures unless (esc_begin && esc_end) || href url = "http://d.hatena.ne.jp/#{id}/#{date}" if sect then sect.gsub!(/^:/, "/") url += sect end "#{pre}<a href=\"#{url}\">#{link}</a>" else matched end } # href: diary new_line = new_line.gsub(/href=['"]\[?(d:)?id:([\w-]+)(:[^\]'"]+)?\]?['"]/i) { |matched| service, id ,path = $~.captures url = "http://d.hatena.ne.jp/#{id}" if path then path.scan(/^:((\d{8})$|(\d{8})(:[\w]+|#[\w]+)$)/) { |s,date1,date2,sect| if date1 then url += "/#{date1}" elsif date2 then sect.gsub!(/^:/, "/") url += "/#{date2}#{sect}" end } end "href=\"#{url}\"" } # href: group new_line = new_line.gsub(/href=['"]\[?g:([\w-]+)(:id:([\w-]+)(:[^\]'"]+)?)?\]?['"]/i) { |matched| group, id_path, id, path = $~.captures url = "http://#{group}.g.hatena.ne.jp" if id then url += "/#{id}" if path then path.scan(/^:((\d{8})$|(\d{8})(:[\w]+|#[\w]+)$)/) { |s,date1,date2,sect| if date1 then url += "/#{date1}" elsif date2 then sect.gsub!(/^:/, "/") url += "/#{date2}#{sect}" end } end end "href=\"#{url}\"" } # href: group keyword new_line = new_line.gsub(/href=['"]\[?g:([\w-]+):keyword:([^\]'']+)\]?['"]/i) { |matched| group, keyword = $~.captures url = "http://#{group}.g.hatena.ne.jp/keyword/#{keyword}" "href=\"#{url}\"" } new_lines.push(new_line) } return new_lines end def print_diff(src_lines, dst_lines) src_lines.each_index { |i| if src_lines[i] != dst_lines[i] then puts "- #{src_lines[i]}" puts "+ #{dst_lines[i]}" end } end check = (ARGV[0] == "check") Dir.glob("#{ORIG_DIR}/????-??-??_*.txt").sort.each { |src| dst = File.basename(src) entry = load_entry_file(src) body = entry[:body] new_body = convert_id_links(entry[:body]) if (body != new_body) then puts "#{src}:" print_diff(body, new_body) unless check then entry[:body] = new_body dump_entry_file(dst, entry) puts "saved: #{dst}" end end }
引数に check を指定するとエントリファイルを置換せずに置換する部分の差分表示だけして終わります。
hbw のエントリファイルのヘッダ部分を読み飛ばすようにしています。また、トラックバック以降作業後の作業ということで、以前の作業で追加したトラックバック部分も読み飛ばすようにしています。
基本的に自分の書き方でヒットするケースのみに対処しているので、人によってはこのままでは足りないかもしれません。またはてなダイアリーとはてなグループ用のリンクにしか対応していません。
修正の実行
hbw を実行しておしまい。
やり残し
確認中に気付いたのですが、a タグの href 属性値に書いたisbn記法やasin記法もはてなブログでは展開してくれないんですね… これは別途対処しようと思います。
もう一つ、フラグメント識別子で日記内のセクションへリンクしている場合(http://d.hatena.ne.jp/rna/20190128#p1 等)、はてなブログに移行したダイアリーでリンク先のセクションに対応するエントリには飛ばないという問題があります。
これははてなの方に要望を投げているとことろです。対応してもらえるとありがたいのですが、ダメだった場合どうするか… 大抵の場合はURLを http://d.hatena.ne.jp/rna/20190128/p1 に置き換えてしまえばエントリに飛ぶんですが、なぜかそうならないブログもあるのです。
例えば上の記事で挙げた飯田さんのブログがそうです。おそらくダイアリーを日記モードで使っているとそうなるのかなとにらんでいますが、元がどっちモードだったかなんてわからないのでどうしたものか…
お詫び
最後に、今回の作業でまたidコールが飛びまくったかもしれません。もしそうでしたらお詫びします。
一応エントリの再編集では追加分のidにしかコールが飛ばないはずなのですが…
でも AtomPub からの編集でもそうなのか不明ですし、差分の取り方によっては追加分と認識されそうなので、やっぱり飛んでしまったかも…
人によっては10年以上も前のブログからコールが飛んできて不快かと思いますが、リンクはWebの命だと思っているのでリンク切れは極力なくしたいのです。どうかお許しください。