github.com/maruel/nin@v0.0.0-20220112143044-f35891e3ce7e/edit_distance.go (about) 1 // Copyright 2011 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package nin 16 17 func editDistance(s1, s2 string, allowReplacements bool, maxEditDistance int) int { 18 // The algorithm implemented below is the "classic" 19 // dynamic-programming algorithm for computing the Levenshtein 20 // distance, which is described here: 21 // 22 // http://en.wikipedia.org/wiki/LevenshteinDistance 23 // 24 // Although the algorithm is typically described using an m x n 25 // array, only one row plus one element are used at a time, so this 26 // implementation just keeps one vector for the row. To update one entry, 27 // only the entries to the left, top, and top-left are needed. The left 28 // entry is in row[x-1], the top entry is what's in row[x] from the last 29 // iteration, and the top-left entry is stored in previous. 30 m := len(s1) 31 n := len(s2) 32 33 row := make([]int, n+1) 34 for i := 1; i <= n; i++ { 35 row[i] = i 36 } 37 38 for y := 1; y <= m; y++ { 39 row[0] = y 40 bestThisRow := row[0] 41 42 previous := y - 1 43 for x := 1; x <= n; x++ { 44 oldRow := row[x] 45 if allowReplacements { 46 v := 0 47 if s1[y-1] != s2[x-1] { 48 v = 1 49 } 50 row[x] = min(previous+v, min(row[x-1], row[x])+1) 51 } else { 52 if s1[y-1] == s2[x-1] { 53 row[x] = previous 54 } else { 55 row[x] = min(row[x-1], row[x]) + 1 56 } 57 } 58 previous = oldRow 59 bestThisRow = min(bestThisRow, row[x]) 60 } 61 62 if maxEditDistance != 0 && bestThisRow > maxEditDistance { 63 return maxEditDistance + 1 64 } 65 } 66 67 return row[n] 68 } 69 70 func min(i, j int) int { 71 if i < j { 72 return i 73 } 74 return j 75 }