気がつけば。diff を実装してから7年も経っていました。
案の定、考え方がかなり頭から抜けて行ってしまっているのですが、当時 diff について詳しい記事を書かれていた方がいらっしゃって、加えてこの記事にリンクを貼ってくださっていたおかげでそれを辿って当該記事にたどり着くことができて、どうにか再実装にこぎつけることができました。感謝です。
C++ で再実装
少々思うところがあって。C++の実装を書き直してみました。
職業プログラマに転向してからは主に Ruby を使っていて、C++ の方はすっかり進歩が止まってしまっていたものと思っていたのですが、それでも7年前のコードを見ると粗が目に付きます。
利用例。
#include <iostream> #include <vector> #include <string> #include "myers.h" int main(int, char* []) { using namespace emattsan::myers; std::string fooBarBaz = "fooBarBaz"; std::string FooBazBar = "FooBazBarfoz"; std::vector<EditType> ses = diff(fooBarBaz, FooBazBar); std::string::const_iterator i1 = fooBarBaz.begin(); std::string::const_iterator i2 = FooBazBar.begin(); std::for_each(ses.begin(), ses.end(), [&](EditType edit_type) { switch(edit_type) { case DELETE: std::cout << "- " << *i1 << std::endl; ++i1; break; case ADD: std::cout << "+ " << *i2 << std::endl; ++i2; break; default: std::cout << " " << *i1 << std::endl; ++i1; ++i2; break; } }); return 0; }
ビルド & 実行。
$ g++ --std=c++11 -o sample sample.cpp $ ./sample - f + F o o B a - r + z B a + r + f + o z
Ruby で再実装
gem 作りの練習をしているので勢いで Ruby で実装してみた。
利用例。
Gemfile 。
gem 'myers_diff', github: 'mattsan/ruby_myers_diff'
サンプル。
require 'myers_diff' FooBarBaz = "fooBarBaz"; FooBazBar = "FooBazBarfoz"; ses = MyersDiff.diff(FooBarBaz, FooBazBar) i1 = FooBarBaz.chars.each i2 = FooBazBar.chars.each ses.each do |edit_type| case edit_type when :DELETE puts "- #{i1.next}" when :ADD puts "+ #{i2.next}" else puts " #{i1.next}" i2.next end end
インストール。
$ bundle install --path vendor/bundle
実行。
$ bundle exec ruby sample.rb - f + F o o B a - r + z B a + r + f + o z