|
|||||
<このサンプルの概要> テキスト差分(Diff)を解析するロジックに興味を持ち色々調べましたが、良い公式を見つ ける事が出来ませんでした。なぜテキスト差分という、今や当たり前のキーワードが公開 されていないのか疑問に思いつつ、仕方無く自力(独自アルゴリズム)で考えました。 このサンプルは、2つのテキストファイルを比較し差分解析結果を返します。まず、変更 前/後のテキストファイルを読み込みます。読み込んだ変更前ファイルを先頭行から差分 解析し変更後ファイルと一致するかを確認します。一致していれば解析済み行としてカウ ントアップします。一致していなければ次の一致行を探します。そこで見つかった一致行 までが差分となります。しかし、変更前ファイルからのみ差分解析すると、実際より差分 が大きくなってしまうので変更後ファイルからの差分解析も行います。変更前ファイルか らの差分解析結果と変更後ファイルからの差分解析結果のを比較し一致行以降の一致行数 が多い方を採用します。そうして得た結果を配列に並べ、変更状態を示す文字列(UPD,ADD, DEL) と共に返します。引数には変更前/後ファイル名以外に精度微調整パラメータ(P1: 一致とみなす文字数、P2:一致とみなす行数)があります。これは、不一致行を発見して から次に一致行とみなる条件です。この値を調整する事により差分解析結果が変わります。 変更前/後のテキストファイルに少しの変更しか無い場合はp1を小さくした方がより現 実的な差分になります。また、変更前/後のテキストファイルに大きな変更を行なった場 合はp1の値を大きくした方が全体的な差分が分かりやすくなります。 このサンプルは「テキスト差分表示ツール」の「Ver2.04」 で使用しているもので最新版 とは異なりますが、基本的な考え方は一緒です。最新版では、不一致行の中から一致行を 再度探す処理を入れ精度を高くしていますが、基本的にはこのバージョンで充分だと思っ ています。また、最新版では文字コードの自動判定を行なっていますが、このサンプルは SJISコードのテキストファイルのみ差分解析が可能です。 バージョンアップ(テキスト差分解析精度向上、文字コード判定)版をライブラリ(DLL) として公開していますのでお試しください。(VBSとVBAでも動作確認しています) テキスト差分解析DLL(VB6/VB.NET/C#.NET) 少し新しいサンプルソースもあります。(差分解析ロジックVer5.01) 2つのテキストファイルの差分を解析するサンプル(VB) VB.NET版のサンプルソースもあります。(差分解析ロジックVer5.01) 2つのテキストファイルの差分を解析するサンプル(VB.NET) 「テキスト差分表示ツール」をダウンロード頂けます。 テキスト差分表示ツール フォルダ監視人 「ネット(Web)で手軽にテキスト差分表示サービス!!」をお試し頂けます。 テキスト差分表示ツール.NET ファイル比較関係のその他のツールやサンプルソースはこちらです。 ファイル比較/フォルダ比較 ' ' 関数名 : TextDiff ' 返り値 : テキスト差分解析結果2次元配列 ' : (正常時) ' : 配列番号=0はタイトル行、配列番号=1以降にテキストデータ ' : 配列(0,0) = "TYPE" ' : 配列(1,0) = "NO." ' : 配列(2,0) = file0PATH ' : 配列(3,0) = "NO." ' : 配列(4,0) = file1PATH ' : 配列(0,1〜) = 変更状態を示す文字列(UPD,ADD,DEL) ' : 配列(1,1〜) = file0の行番号 ' : 配列(2,1〜) = file0の各行テキストデータ ' : 配列(3,1〜) = file1の行番号 ' : 配列(4,1〜) = file1の各行テキストデータ ' : (エラー時) ' : 配列(0,0) = -1 ' : 配列(1,0) = エラーメッセージ ' 引き数 : file0(i) : 変更前テキストファイル ' : file1(i) : 変更後テキストファイル ' : p1 (i) : 精度微調整パラメータ(一致とみなす文字数) ' : p2 (i) : 精度微調整パラメータ(一致とみなす行数) ' 機能説明 : テキストファイルを比較し、テキスト差分解析結果を返します ' 備考 : テキスト差分解析ロジックVer2.04 ' 著作権 : Copyright(C) 2008 のん All rights reserved ' --------------------------------------------------------------------------- ' 使用条件 : このサイトの内容を使用(流用/改変/転載/等全て)した成果物を不特定 ' : 多数に公開/配布する場合は、このサイトを参考にした旨を記述してく ' : ださい。(例)WEBページやReadMeにリンクを貼ってください ' --------------------------------------------------------------------------- Public Function TextDiff(ByVal file0 As String, ByVal file1 As String, _ Optional ByVal p1 As Long = 5, _ Optional ByVal p2 As Long = 1) As String() On Error Resume Next Dim rtn() As String ' テキスト差分解析結果2次元配列定義 ReDim rtn(4, 0) ' テキスト差分解析結果2次元配列定義 Dim dfp As Long ' テキスト差分解析結果の現在の配列番号保存用 Dim diff As Boolean ' テキスト差分発見フラグ Dim i As Long ' カウンタ(変更前テキストファイル側) Dim j As Long ' カウンタ(変更後テキストファイル側) Dim k As Long ' カウンタ(汎用) Dim tmps As String ' 文字列(汎用) Dim fit0 As Long ' 一致行番号(変更前テキストファイル側) Dim fit1 As Long ' 一致行番号(変更後テキストファイル側) Dim sumi0 As Long ' 解析済行番号(変更前テキストファイル側) Dim sumi1 As Long ' 解析済行番号(変更後テキストファイル側) Dim OrgFile0() As String ' 変更前テキストファイル読込配列 Dim OrgFile1() As String ' 変更後テキストファイル読込配列 Dim txtfile0 As TextStream ' 変更前テキストファイルストリーム Dim txtfile1 As TextStream ' 変更後テキストファイルストリーム Dim fso As FileSystemObject ' ファイルシステムオブジェクト Set fso = CreateObject("Scripting.FileSystemObject") ' ファイル読込領域クリア ReDim OrgFile0(0) ReDim OrgFile1(0) If file0 <> "" Then ' 変更前ファイル存在チェック If fso.FileExists(file0) = False Then rtn(0, 0) = "-1" rtn(1, 0) = "ファイルが存在しません" & vbCrLf & vbCrLf & file0 TextDiff = rtn Exit Function End If ' 変更前ファイルオープン Set txtfile0 = fso.OpenTextFile(file0, ForReading, False) If txtfile0 Is Nothing Then rtn(0, 0) = "-1" rtn(1, 0) = "ファイルを読み込めません " & vbCrLf & vbCrLf & file0 TextDiff = rtn Exit Function End If ' 変更前ファイル読込 Do While txtfile0.AtEndOfStream <> True ReDim Preserve OrgFile0(UBound(OrgFile0) + 1) OrgFile0(UBound(OrgFile0)) = txtfile0.ReadLine Loop ' 変更前ファイルクローズ txtfile0.Close End If If file1 <> "" Then ' 変更前ファイル存在チェック If fso.FileExists(file1) = False Then rtn(0, 0) = "-1" rtn(1, 0) = "ファイルが存在しません" & vbCrLf & vbCrLf & file1 TextDiff = rtn Exit Function End If ' 変更後ファイルオープン Set txtfile1 = fso.OpenTextFile(file1, ForReading, False) If txtfile1 Is Nothing Then rtn(0, 0) = "-1" rtn(1, 0) = "ファイルを読み込めません " & vbCrLf & vbCrLf & file1 TextDiff = rtn Exit Function End If ' 変更後ファイル読込 Do While txtfile1.AtEndOfStream <> True ReDim Preserve OrgFile1(UBound(OrgFile1) + 1) OrgFile1(UBound(OrgFile1)) = txtfile1.ReadLine Loop ' 変更後ファイルクローズ txtfile1.Close End If ' テキスト差分解析開始 sumi0 = 0 sumi1 = 0 Do If sumi0 >= UBound(OrgFile0) And sumi1 >= UBound(OrgFile1) Then ' テキスト差分解析終了 Exit Do End If ' テキスト差分発見フラグクリア diff = False 只今、都合によりサンプルソースの公開を停止しています。 申し訳ございませんが、テキスト差分解析DLL(VB6/VB.NET/C#.NET)でお試しください。 ' 変更行をテキスト差分解析結果2次元配列へ設定 If fit0 - 1 - sumi0 > 0 And fit1 - 1 - sumi1 > 0 Then dfp = UBound(rtn, 2) ' 変更行をテキスト差分解析結果2次元配列に設定(変更前) For k = sumi0 + 1 To fit0 - 1 If UBound(rtn, 2) < dfp + k - sumi0 Then ReDim Preserve rtn(4, UBound(rtn, 2) + 1) End If rtn(0, dfp + k - sumi0) = "UPD" rtn(1, dfp + k - sumi0) = k rtn(2, dfp + k - sumi0) = OrgFile0(k) Next k ' 変更行をテキスト差分解析結果2次元配列に設定(変更後) For k = sumi1 + 1 To fit1 - 1 If UBound(rtn, 2) < dfp + k - sumi1 Then ReDim Preserve rtn(4, UBound(rtn, 2) + 1) End If rtn(0, dfp + k - sumi1) = "UPD" rtn(3, dfp + k - sumi1) = k rtn(4, dfp + k - sumi1) = OrgFile1(k) Next k ElseIf fit0 - 1 - sumi0 > 0 And fit1 - 1 - sumi1 <= 0 Then ' 削除行をテキスト差分解析結果2次元配列に設定 For k = sumi0 + 1 To fit0 - 1 ReDim Preserve rtn(4, UBound(rtn, 2) + 1) rtn(0, UBound(rtn, 2)) = "DEL" rtn(1, UBound(rtn, 2)) = k rtn(2, UBound(rtn, 2)) = OrgFile0(k) Next k ElseIf fit0 - 1 - sumi0 <= 0 And fit1 - 1 - sumi1 > 0 Then ' 追加行をテキスト差分解析結果2次元配列に設定 For k = sumi1 + 1 To fit1 - 1 ReDim Preserve rtn(4, UBound(rtn, 2) + 1) rtn(0, UBound(rtn, 2)) = "ADD" rtn(3, UBound(rtn, 2)) = k rtn(4, UBound(rtn, 2)) = OrgFile1(k) Next k End If ' 一致行をテキスト差分解析結果2次元配列に設定 If fit0 <= UBound(OrgFile0) And fit1 <= UBound(OrgFile1) Then ReDim Preserve rtn(4, UBound(rtn, 2) + 1) rtn(1, UBound(rtn, 2)) = fit0 rtn(2, UBound(rtn, 2)) = OrgFile0(fit0) rtn(3, UBound(rtn, 2)) = fit1 rtn(4, UBound(rtn, 2)) = OrgFile1(fit1) End If ' 解析済み行の設定 sumi0 = fit0 sumi1 = fit1 Loop ' タイトル行設定 rtn(0, 0) = "TYPE" rtn(1, 0) = "NO." rtn(2, 0) = file0 rtn(3, 0) = "NO." rtn(4, 0) = file1 ' ファイルシステムオブジェクト解放 Set fso = Nothing ' リターン TextDiff = rtn End Function |