文書比較のアルゴリズム
- - PR -
UNIXのdiffコマンドをご存じでしょうか。テキスト同士を比較して違いを表示するコマンドです。
ECサイトの多くでは、商品の感想の書き込み機能があります。感想が書き込まれたときは、そのまま掲載せず、サイト運営者が内容をチェックしてから誤字脱字などを校正します。その校正のときに、diffと同じように変更前と変更後の差分を表示してから確認する機能があると便利です。
こういった文書比較は、一見ひたすら総当りで泥臭いプログラムになっていそうです。しかし、実は非常にスマートなアルゴリズムで実現されています。そのアルゴリズムはエディットグラフという図を利用するものです。
エディットグラフ
では、具体的にどういったアルゴリズムになるのか見ていきましょう。
変更前のテキストと変更後のテキストを縦軸と横軸に並べます。左上から右下に最短距離で移動する方法を考えます。このとき縦と横の文字が同じ場合は斜めに移動できるものとします。

まず、縦と横に同じ文字があるところは斜めに移動できるので斜線を引きます。あとはすべての経路の中で斜めを一番多く通る経路を見つけます。

この経路に従って移動していきます。縦移動の場合は、縦軸の文字が変更によって消えたことを表します。横移動の場合は、横軸の文字が変更によって増えたことを表します。消えた文字を横線、追加された文字を太字で表すと次のようになります。
エディットグラフの実装(前半)
それではエディットグラフを実装してみましょう。長いので半分に分けて解説します。
●エディットグラフのソースコード(前半)
1 <html>
2 <head>
3 <script type="text/javascript">
4 function getStringById(id) {
5 var element = document.getElementById(id);
6 var str = element.value;
7 if (str == undefined) {
8 str = element.innerHTML;
9 }
10 return (str == undefined) ? "" : str;
11 }
12
13 window.onload = function() {
14 var text = getStringById('text');
15 document.getElementById('area').innerHTML = text;
16 }
17
18 function minus_ch(ch) {
19 return '<span class="minus">' + ch + '</span>';
20 }
21
22 function plus_ch(ch) {
23 return '<span class="plus">' + ch + '</span>';
24 }
25 </script>
26 <style type="text/css">
27 span.plus { background-color:#FFFF00; font-weight:bold }
28 span.minus { background-color:#FF0000; text-decoration:line-through }
29 </style>
30 </head>
31
32 <body>
33
34 <div id="text">テキスト差分のとり方</div><br>
35 <textarea id="area" rows="10" cols="100"></textarea><br>
36
37 <script type="text/javascript">
38 var EGD_X = 0;
39 var EGD_Y = 1;
40 var EGD_XY = 2;
41 var EGD_END = 3;
42
43 function makeEditGraph(str1, str2) {
44 var edit_graph = new Array();
45
46 edit_graph[str1.length] = new Array();
47 edit_graph[str1.length][str2.length] =
48 {cost:0, direction:EGD_END};
49
50 for (var x = str1.length-1; 0 <= x; x--) {
51 edit_graph[x] = new Array();
52 edit_graph[x][str2.length] = {cost:str1.length-x, direction:EGD_X};
53 }
54 for (var y = str2.length-1; 0 <= y; y--) {
55 edit_graph[str1.length][y] = {cost:str2.length-y, direction:EGD_Y};
56 }
57
58 for (var x = str1.length-1; 0 <= x; x--) {
59 for (var y = str2.length-1; 0 <= y; y--) {
60 var cost;
61 var direction;
62 if (edit_graph[x+1][y].cost <= edit_graph[x][y+1].cost) {
63 cost = edit_graph[x+1][y].cost;
64 direction = EGD_X;
65 } else {
66 cost = edit_graph[x][y+1].cost;
67 direction = EGD_Y;
68 }
69
70 if((str1.charAt(x) == str2.charAt(y))
71 && (edit_graph[x+1][y+1].cost <= cost)) {
72 cost = edit_graph[x+1][y+1].cost;
73 direction = EGD_XY;
74 }
75
76 edit_graph[x][y] = {cost:cost+1, direction:direction};
77 }
78 }
79
80 return edit_graph;
81 }
82 //末尾1- 4〜11行目
- 汎用関数です。指定したIDのHTMLを取得します。
- 13〜16行目
- 初期表示のときに差分結果のところに変更前の文字列を表示しておきます。
- 18〜24行目
- 消えた文字、増えた文字のHTMLを返す関数です。
- 38〜41行目
- エディットグラフの進む方向を表す定数を定義しています。
- 44行目
- edit_graphという変数がエディットグラフ全体を表します。縦と横の2次元配列になっています。それぞれの要素は右下からの移動距離(cost)と次に進む方向(direction)を持っています。
- 46〜48行目
- グラフの右下は移動距離0、移動方向は「なし(EGD_END)」です。
- 50〜53行目
- グラフの一番下の行は、常に右に移動するのが最短距離になるのでそれを設定します。
- 54〜56行目
- 同様にグラフの一番右は、常に下に移動するのが最短距離になります。
- 58〜78行目
- 右下から1つ左上に行った点から、すべての点について移動の方向と距離を計算していきます。
- 62〜68行目
- 下に移動するか、右に移動するか、どちらのほうが移動距離が少なくて済むか比較して、その点の移動距離と方向を決めます。
- 70〜74行目
- 縦と横の文字が同じ場合は斜めに移動できます。
ここまでで、すべての点について方向と移動距離が計算されます。合わせて最短距離の経路も決定します。
2/5 |
| Index | |
| レコメンデーションとエディットグラフ | |
| Page1 実際のアプリケーションで使われるアルゴリズム レコメンデーション 協調フィルタリングの実装 |
|
| Page2 文書比較のアルゴリズム エディットグラフ エディットグラフの実装(前半) |
|
| Page3 エディットグラフの実装(後半) より効率的なエディットグラフ |
|
| Page4 O(ND)アルゴリズムの実装 連載の終わりに |
|
| Appendix 協調フィルタリングの実装(全ソースコード) |
|
| コーディングに役立つ! アルゴリズムの基本 |
| Coding Edgeお勧め記事 |
| いまさらアルゴリズムを学ぶ意味 コーディングに役立つ! アルゴリズムの基本(1) コンピュータに「3の倍数と3の付く数字」を判断させるにはどうしたらいいか。発想力を鍛えよう |
|
| Zope 3の魅力に迫る Zope 3とは何ぞや?(1) Pythonで書かれたWebアプリケーションフレームワーク「Zope 3」。ほかのソフトウェアとは一体何が違っているのか? |
|
| 貧弱環境プログラミングのススメ 柴田 淳のコーディング天国 高性能なIT機器に囲まれた環境でコンピュータの動作原理に触れることは可能だろうか。貧弱なPC上にビットマップの直線をどうやって引く? |
|
| Haskellプログラミングの楽しみ方 のんびりHaskell(1) 関数型言語に分類されるHaskell。C言語などの手続き型言語とまったく異なるプログラミングの世界に踏み出してみよう |
|
| ちょっと変わったLisp入門 Gaucheでメタプログラミング(1) Lispの一種であるScheme。いくつかある処理系の中でも気軽にスクリプトを書けるGaucheでLispの世界を体験してみよう |
|
TechTargetジャパン
Coding Edge フォーラム 新着記事
- 実例で学ぶRailsアプリのテスト方法 (2011/12/22)
具体的なWebアプリを例に簡単なテストを使ったリファクタリングについ
て解説する - Railsの人気テストフレームワーク6選! (2011/8/18)
今回からテストを使ったリファクタリングを解説する。まずはRailsで人
気のあるテストフレームワークをいくつか紹介する - ActiveRecordの更新系操作 (2011/6/27)
Railsのモデル層を担当するActiveRecordを使った登録、更新、削除
など、更新系の機能を中心に見ていきます - 実例アプリで学ぶ“Railsらしさ”の基礎 (2011/5/26)
Ruby on Railsで書かれた実例アプリを取り上げて、初心者が陥りがちなコードの書き方を指摘します。より「Railsらしい」コードとは?
|
|
@IT 新着記事
キャリアアップ
スポンサーからのお知らせ
イベントカレンダー
お勧め求人情報
転職/派遣情報を探す
**先週の人気講座ランキング**
〜 Android編 〜
ホワイトペーパー(TechTargetジャパン)
ソリューションFLASH

