2006年11月18日

普通のdiffは行単位での差分を取るんですが、一行の中での差分がどうしても取りたくてString::Diff(2008/06/24リンク切れなおしたtokuhirom++)ってのを作りました。
既存のCPANモジュールだとString::ShowDiffが微妙に近かったんですが、目的の事が出来ないので作りました。

出来ることは
文字列同士の差分を作って変更無い場所、変更が合った場所で配列を分けて作成。

  my $diff = String::Diff::diff_fully('this is Perl', 'this is Ruby');
for my $line (@{ $diff->[0] }) {
print "$line->[0]: '$line->[1]'\n";
}
# u: 'this is '
# -: 'Perl'

for my $line (@{ $diff->[1] }) {
print "$line->[0]: '$line->[1]'\n";
}
# u: 'this is '
# +: 'Ruby'


差分の合った部分にマークを付ける。htmlタグとか入れられるのでwebにも使えます。
  my $diff = String::Diff::diff('this is Perl', 'this is Ruby');
print "$diff->[0]\n";# this is [Perl]
print "$diff->[1]\n";# this is {Ruby}

my $diff = String::Diff::diff('this is Perl', 'this is Ruby',{
remove_open => '<del>',
remove_close => '</del>',
append_open => '<ins>',
append_close => '</ins>',
});
print "$diff->[0]\n";# this is <del>Perl</del>
print "$diff->[1]\n";# this is <ins>Ruby</ins>


差分同士の結果をマージして一つの文字列にする。
  my $diff = String::Diff::diff_merge('this is Perl', 'this is Ruby'{
remove_open => '<del>',
remove_close => '</del>',
append_open => '<ins>',
append_close => '</ins>',
});
print "$diff\n";# this is <del>Perl</del><ins>Ruby</ins>

そのマージを正規表現のパターンにしてしまう。
  my $diff = String::Diff::diff_regexp('this is Perl', 'this is Ruby');
print "$diff\n";# this\ is\ (?:Perl|Ruby)

tracの差分表示っぽいのが簡単に作れると思います。
実際hatena wikiでそれっぽく実装しました。

これで20個めのCPANモジュールか。

Posted by Yappo at 2006年11月18日 14:00 | TrackBack | Perl
Comments

String::Diffダウンロードさせていただきました。日本語文の差分をとろうとすると、文字化けしてしまいます。2バイト文字の途中で切られているという感じです。

うまいこと、これを避けて使う方法をご存じないでしょうか。

Posted by: 平山 at 2007年08月16日 16:10

どう使われているのかがわからないと何ともコメントできないのですが、いかがでしょうか。

Posted by: Yappo at 2007年08月21日 18:35

遅くなりましてすみません。
日本語文字の差分をとりたいと思っています。


$str1 = 'あいうえこかき';
$str2 = 'あいうえおかさ';
$diff = String::Diff::diff_fully($str1, $str2);
@diff_list = ();
for my $line (@{ $diff->[0] }) {
if ($line->[0] eq '+' || $line->[0] eq '-') {
push(@diff_list, $line->[1]);
}
}

とすると、@diff_list に
'こ','き'が入ることを期待するのですが、なんか文字化けしてしまいます。
英数文字だとうまくいくのですが・・・

Posted by: 平山 at 2007年08月23日 17:34

$str1と$str2がutf8フラグ立ってないせいですね。
utf8フラグ立たせないとwidth charの途中のbyteとかでdiffっちゃうので大変な事になります。

Posted by: Yappo at 2007年08月23日 17:44

ありがとうございます。
utf8フラグというものがあるのですね。

htmlをはき出すCGIなんですが、
スクリプトの文字コードをutf-8にして
use utf8;
の1行を入れるとうまくいきました。
しかし、htmlの書き出しで
Wide character in print
が大量に発生するので、
utf8::encode()
でutf8フラグを落とす手間がかかるようになりました。

スクリプトは元の文字コード(Shift-jis)のままで
utf8フラグを立てるには、別にEncodeモジュール
などが必要になるのでしょうか。

Posted by: 平山 at 2007年08月24日 11:26

What do I really want to see? I'd love to see Apple make a functional touch-screen double-din car stereo. Heck, the demand is there and growing. Ipod integration kits are becoming de rigeur so what's the missing link? Think about having cover flow on your car stereo display or the ability to use apps in your car via your iphone's data link. Or a one-click purchase of songs you hear on the radio that automatically downloads them via iTunes. If you want to know what the next, "One more thing..." is, you need look no further than the lousy radio in your car. El Jobso won't let Microsoft and their Sync platform run hog wild in automobiledom for too long. You've heard it here first - now spread the word. of course what i talk is far from Cheap Nokia Mobile Phone
Cheap Mobile Phone Deal
Car Audio Store
Wholesale Consumer Electronics , but we try to do better .

Posted by: cell phone watches at 2009年02月17日 17:09
Post a comment









Remember personal info?






コメントを投稿する前に↓の場所にnospamと入力してください。