【VBA】一致率の可視化(レーベンシュタイン距離)続
以前、Excelでレーベンシュタイン距離を見えるようにした記事を投稿しました。
書いた当時は、こんな記事はほとんど見られないだろうと思っていたのですが、
意外や意外、このサイト内でトップ3に入る注目記事となっています。
そこで、今度はこの手順をワークシートの関数ではなく、VBAで実装してみました。
Rosetta Codeをのぞいてみる
レーベンシュタイン距離は二重ループを回すのが基本だと思いますが、
ここは少し手を抜いて、Rosetta Codeの実装例を見てみます。
やはり、二重ループですね。
というわけでこれを魔改造してみましょう。
Option Explicit
Option Base 1
Public Sub levenshtein(s1 As String, s2 As String)
Dim n As Integer: n = Len(s1) + 1
Dim m As Integer: m = Len(s2) + 1
' ### 追加部分 ###
'長い方の文字数を取得するのと、文字列を一文字ずつ格納した配列を用意する
'文字の配列は一括で代入するため、二次元配列にしておく
Dim lr As Integer
If n >= m Then
lr = n
Else
lr = m
End If
Dim s1s() As String, s2s() As String
ReDim s1s(n, 1)
ReDim s2s(1, m)
' ### 追加ここまで ###
Dim d() As Integer, i As Integer, j As Integer
ReDim d(n, m)
If n = 1 Or m = 1 Then
Exit Sub
End If
For i = 1 To n
d(i, 1) = i - 1
' ### 追加部分 ###
'文字列を1文字ずつ入れておく
s1s(i, 1) = Mid(s1, i, 1)
' ### 追加ここまで ###
Next i
For j = 1 To m
d(1, j) = j - 1
' ### 追加部分 ###
'文字列を1文字ずつ入れておく
s2s(1, j) = Mid(s2, j, 1)
' ### 追加ここまで ###
Next j
For i = 2 To n
For j = 2 To m
d(i, j) = WorksheetFunction.Min( _
d(i - 1, j) + 1, _
d(i, j - 1) + 1, _
(d(i - 1, j - 1) - (Mid(s1, i - 1, 1) <> Mid(s2, j - 1, 1))) _
)
Next j
Next i
' ### 追加部分 ###
' ワークシートに書き出しをする
With ThisWorkbook.Sheets(1)
.Range("A5").Value = "結果"
.Range("B5").Value = "'" & d(n, m) & " / " & lr
.Range("C5").Value = 1 - d(n, m) / (lr - 1)
.Range("A8").Resize(n, 1) = s1s
.Range("C6").Resize(1, m) = s2s
.Range("B7").Resize(i - 1, j - 1) = d
.Range("A5").Select
End With
' ### 追加ここまで ###
End Sub
' ### 呼び出し用の関数を変更
Public Sub main()
' ### 古いデータを削除
Call clear_old
' ### ワークシート上のデータを利用
With ThisWorkbook.Sheets(1)
Call levenshtein(.Range("B2").Text, .Range("B3").Text)
End With
End Sub
Private Sub clear_old()
With ThisWorkbook.Sheets(1)
.Range("A5").Select
Range(Selection, ActiveCell.SpecialCells(xlLastCell)).Select
Selection.ClearContents
End With
End Sub
これで改造は完了です。
試してみる
次に、ワークシートを作っていきます。
コードにも書いてあるとおり、B2とB3に文字列を記入できるようにしています。
さらにマクロの実行ボタンも追加しておきましょう。

あとは実行ボタンにプロシージャ main を登録するだけです。
前回と同じ文を入力して実行ボタンを押すと……

すぐに結果が表示されます。
実用化の予定
一文同士の比較であれば、VBAでのレーベンシュタイン距離の計算もいけそうですね。
この用途としては、微妙な修正テキストやチェック前/後の比較などを検討中です。
それには getOcode のような、何文字目がどう違うのかを求めるプログラムが必要になりそうですが……
次はこの部分についても実装していきたいと思います。
2021/5/20 追記
WordにてgetOcodeを含むSequanceMatcherを実装し、差分確認できるようにしたマクロについて、記事を公開しました。

MS Office Wordと接続。軽量型でWYSIWYGを実現