HTMLファイルの差分を表示するようなスクリプト。
まずPEARを見たが、そのものズバリはないけど、Text_Diffというのがあった。
- PEAR :: Package :: Text_Diff
http://pear.php.net/package/Text_Diff - PEAR :: Package :: Text_Highlighter
http://pear.php.net/package/Text_Highlighter - PHP: xdiff Functions - Manual
http://jp2.php.net/manual/ja/ref.xdiff.php
Perlだとそれっぽいのがあるような感じだ。
ロジックは割合単純そうなPythonのものというのもあった。
- HTML Diff
http://www.aaronsw.com/2002/diff/
HTML Diff is a simple Python program that uses Python's difflib to highlight changes in HTML documents
PerlやPythonの例を見ると、結局、HTMLのタグを区切りにして、HTMLの文字列を細かく切り刻んでから、diffを取ればいいようだ、ということになった。
また、日本語で一行が長い時に、まるまる一行が差分になってしまうのは嫌なので、適当に区切りたい。以下を参考に文字の種類で半角、全角などの境い目で区切る。
- MODULE.JP - 日本語に絡むUnicodeブロックとスクリプト(正規表現)
http://module.jp/blog/regex_unicode_prop.html - Perlメモ 文字の正規表現
http://www.din.or.jp/~ohzaki/perl.htm#Character
/*
* シフトJISにおける文字種別の定義
* ref. http://module.jp/blog/regex_unicode_prop.html
* ref. http://www.din.or.jp/~ohzaki/perl.htm#Character
*/
$latin1 = '[\x21-\x7E]'; // Latin-1
$hankana = '[\xA6-\xDF]'; // 半角カナ
$zenhira = '(?:\x82[\x9F-\xF1])'; // 全角ひらがな
$zenkana = '(?:\x83[\x40-\x96])'; // 全角カタカナ
//$kanji = '(?:[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])'; // シフトJIS文字全体
$kanji1 = '(?:\x81[\x40-\x7E\x80-\xFC])'; // 0x81 ひらがなより前
$kanji2 = '(?:\x82[\x40-\x7E\x80-\x9E])'; // 0x82 ひらがなより前
$kanji3 = '(?:\x83[\x97-\xFC])'; // 0x83 カタカナより後
$kanji4 = '(?:[\x84-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])'; // それ以外
/** シフトJISにおいて文字種別で分割する正規表現 */
$regex_char_type = "{$latin1}+|{$hankana}+|{$zenhira}+|{$zenkana}+|(?:{$kanji1}|{$kanji2}|{$kanji3}|{$kanji4})+";
/** HTMLのコメント、タグと単語で区切る正規表現 */
$regex_sep_tags_words = '/(<!--.*-->|<[^>]*>|(?:'.$regex_char_type.'))/s';
$html1 = file_get_contents($filename1);
$html2 = file_get_contents($filename2);
$html1 = preg_split($regex_sep_tags_words, $html1, -1, PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE);
$html2 = preg_split($regex_sep_tags_words, $html2, -1, PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE);
require_once 'Text/Diff.php';
$diff = &new Text_Diff($html1, $html2);色々なデータを試すときっともう少し改良の余地はあると思うけど、とりあえずこんな感じになった。(例えば上記の正規表現だとアルファベットの後にタグがあると分けられない。abc<br>など。)
後はdiffを<ins>や<del>で囲めば、それらしく見えるものができる。
本当はText_Diff_Rendererを実装するのが本筋なのかもしれない。