LoginSignup
1
0

More than 3 years have passed since last update.

文字単位の差分を取ってHTMLタグをつける

Last updated at Posted at 2019-10-11

文字単位のdiffを取って、いい感じにHTMLで表示したくなることありませんか? ぼくはあります。
ただ、この前それをやりたくなったのが10年以上前で、すっかり忘れてまた作り直すはめになったので、自分用を兼ねてメモしておきます。

欲しいのはこういうやつです。

$ echo -e "今日はいい天気ですね。\t今日はとてもいい天気でしたね" | xxx
今日は<u>とても</u>いい天気で<s>す</s><u>した</u>ね<s>。</s>

入力はタブ区切りで、左右の行は常に対応しているとします。対応していない場合はちゃんとしたツールを使って何とかしたほうがいいと思いますが、ここでは行は対応しているとして、その場合の文字単位のdiffをワンライナーで取ることにします。

Perlで書いたワンライナーが次のものです。

perl -MFile::Temp -Mutf8 -CSD -F/\\t/ -nale 'for $i(0..1) { ($fh[$i], $fname[$i]) = File::Temp::tempfile(UNLINK=>1); binmode $fh[$i], ":utf8"; @{$l[$i]} = split//, $F[$i]; print {$fh[$i]} $_ for @{$l[$i]}; close $fh[$i]; } for (reverse grep { m{^\d}; } map { chomp; $_; } `diff $fname[0] $fname[1]`) { @t = map { m{^(\d+),(\d+)$} ? [$1-1, $2-1] : m{^(\d+)$} ? [$1-1, $1-1] : $_; } split/([acd])/; @new = @{$l[1]}[$t[2]->[0]..$t[2]->[1]]; if ($t[1] eq "a") { splice @{$l[0]}, $t[0]->[0]+1, 0, "<u>", @new, "</u>"; } elsif ($t[1] eq "d") { splice @{$l[0]}, $t[0]->[1]+1, 0, "</s>"; splice @{$l[0]}, $t[0]->[0], 0, "<s>"; } else { splice @{$l[0]}, $t[0]->[1]+1, 0, "</s><u>", @new, "</u>"; splice @{$l[0]}, $t[0]->[0], 0, "<s>"; } } print join("", @{$l[0]});'

Gist

これを使うと、上のことが実現できます。

echo -e "今日はいい天気ですね。\t今日はとてもいい天気でしたね" | perl -MFile::Temp -Mutf8 -CSD -F/\\t/ -nale 'for $i(0..1) { ($fh[$i], $fname[$i]) = File::Temp::tempfile(UNLINK=>1); binmode $fh[$i], ":utf8"; @{$l[$i]} = split//, $F[$i]; print {$fh[$i]} $_ for @{$l[$i]}; close $fh[$i]; } for (reverse grep { m{^\d}; } map { chomp; $_; } `diff $fname[0] $fname[1]`) { @t = map { m{^(\d+),(\d+)$} ? [$1-1, $2-1] : m{^(\d+)$} ? [$1-1, $1-1] : $_; } split/([acd])/; @new = @{$l[1]}[$t[2]->[0]..$t[2]->[1]]; if ($t[1] eq "a") { splice @{$l[0]}, $t[0]->[0]+1, 0, "<u>", @new, "</u>"; } elsif ($t[1] eq "d") { splice @{$l[0]}, $t[0]->[1]+1, 0, "</s>"; splice @{$l[0]}, $t[0]->[0], 0, "<s>"; } else { splice @{$l[0]}, $t[0]->[1]+1, 0, "</s><u>", @new, "</u>"; splice @{$l[0]}, $t[0]->[0], 0, "<s>"; } } print join("", @{$l[0]});'
今日は<u>とても</u>いい天気で<s>す</s><u>した</u>ね<s>。</s>

中でdiffコマンドを実行しているので、diffコマンドが入っていることが必要です。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0