claude go reimplement
This commit is contained in:
1 parent
4bcb924158
commit
f523c79618
83 files changed
+3714
-3454
No files matched your search
@@ -0,0 +1,76 @@
|
||||
package kjv
|
||||
|
||||
// Ratcliff/Obershelp string similarity (the ratio of matching characters) and
|
||||
// a closest match lookup, which the fuzzy book name matching relies on.
|
||||
|
||||
type matchBlock struct{ a, b, size int }
|
||||
|
||||
func longestMatch(a, b []rune, alo, ahi, blo, bhi int) matchBlock {
|
||||
besti, bestj, bestsize := alo, blo, 0
|
||||
prev := make([]int, len(b)+1)
|
||||
cur := make([]int, len(b)+1)
|
||||
for i := alo; i < ahi; i++ {
|
||||
for j := blo; j < bhi; j++ {
|
||||
if a[i] != b[j] {
|
||||
cur[j+1] = 0
|
||||
continue
|
||||
}
|
||||
k := prev[j] + 1
|
||||
cur[j+1] = k
|
||||
if k > bestsize {
|
||||
besti, bestj, bestsize = i-k+1, j-k+1, k
|
||||
}
|
||||
}
|
||||
prev, cur = cur, prev
|
||||
for j := range cur {
|
||||
cur[j] = 0
|
||||
}
|
||||
}
|
||||
return matchBlock{besti, bestj, bestsize}
|
||||
}
|
||||
|
||||
func matchedChars(a, b []rune) int {
|
||||
type span struct{ alo, ahi, blo, bhi int }
|
||||
queue := []span{{0, len(a), 0, len(b)}}
|
||||
total := 0
|
||||
for len(queue) > 0 {
|
||||
q := queue[len(queue)-1]
|
||||
queue = queue[:len(queue)-1]
|
||||
m := longestMatch(a, b, q.alo, q.ahi, q.blo, q.bhi)
|
||||
if m.size == 0 {
|
||||
continue
|
||||
}
|
||||
total += m.size
|
||||
if q.alo < m.a && q.blo < m.b {
|
||||
queue = append(queue, span{q.alo, m.a, q.blo, m.b})
|
||||
}
|
||||
if m.a+m.size < q.ahi && m.b+m.size < q.bhi {
|
||||
queue = append(queue, span{m.a + m.size, q.ahi, m.b + m.size, q.bhi})
|
||||
}
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
func similarity(a, b string) float64 {
|
||||
ra, rb := []rune(a), []rune(b)
|
||||
if len(ra)+len(rb) == 0 {
|
||||
return 1
|
||||
}
|
||||
return 2.0 * float64(matchedChars(ra, rb)) / float64(len(ra)+len(rb))
|
||||
}
|
||||
|
||||
// closestMatch is the best scoring possibility with a ratio of at least cutoff.
|
||||
// Ties on score go to the lexicographically larger possibility.
|
||||
func closestMatch(word string, possibilities []string, cutoff float64) (string, bool) {
|
||||
best, bestScore, found := "", 0.0, false
|
||||
for _, p := range possibilities {
|
||||
score := similarity(p, word) // difflib compares possibility (a) against word (b)
|
||||
if score < cutoff {
|
||||
continue
|
||||
}
|
||||
if !found || score > bestScore || (score == bestScore && p > best) {
|
||||
best, bestScore, found = p, score, true
|
||||
}
|
||||
}
|
||||
return best, found
|
||||
}
|
||||
Reference in new issue
Block a user