Fold names by Unicode decomposition in Normalize
CI / ci (push) Successful in 2m4s
CI / ci (pull_request) Successful in 1m32s

Replace the hand-written accent map with letterFolds, a table generated
offline by gen_folds.py from Python's unicodedata: every code point whose
canonical decomposition contains combining marks maps to its base letters,
plus stroked Latin letters and ligatures. Combining marks are still dropped,
so composed and decomposed spellings ("Phở" and "Phở") now
normalize equal. No new dependency.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-05 08:50:42 -04:00
co-authored by Claude Opus 5.5
parent 1e0b1fc75e
commit 7729488cde
5 changed files with 1314 additions and 21 deletions
+6 -19
View File
@@ -16,25 +16,12 @@ var fillerWords = map[string]bool{
"the": true, "a": true, "recipe": true, "classic": true,
}
// accentFolds maps each lowercase accented Latin letter to its plain form.
var accentFolds = func() map[rune]string {
m := map[rune]string{'ß': "ss", 'æ': "ae", 'œ': "oe", 'þ': "th", 'ð': "d"}
for plain, accented := range map[string]string{
"a": "àáâãäåāăą", "c": "çćĉċč", "d": "ďđ", "e": "èéêëēĕėęě",
"g": "ĝğġģ", "h": "ĥħ", "i": "ìíîïĩīĭįı", "j": "ĵ", "k": "ķ",
"l": "ĺļľŀł", "n": "ñńņňʼn", "o": "òóôõöøōŏő", "r": "ŕŗř",
"s": "śŝşšș", "t": "ţťŧț", "u": "ùúûüũūŭůűų", "w": "ŵ", "y": "ýÿŷ",
"z": "źżž",
} {
for _, r := range accented {
m[r] = plain
}
}
return m
}()
//go:generate python3 gen_folds.py
// Normalize returns the comparable form of a dinner name: lowercased,
// accents folded to plain letters, apostrophes removed, other punctuation
// combining marks (Unicode category Mn) dropped, precomposed and stroked
// letters folded to their base letters (see letterFolds) so composed and
// decomposed spellings are equal, apostrophes removed, other punctuation
// turned into spaces, filler words (see fillerWords) dropped and whitespace
// collapsed to single spaces. "Easy Chicken Tikka-Masala!" becomes
// "chicken tikka masala".
@@ -44,8 +31,8 @@ func Normalize(name string) string {
switch {
case unicode.Is(unicode.Mn, r), r == '\'', r == '’':
// Combining accents and apostrophes join their neighbours.
case accentFolds[r] != "":
b.WriteString(accentFolds[r])
case letterFolds[r] != "":
b.WriteString(letterFolds[r])
case unicode.IsLetter(r), unicode.IsDigit(r):
b.WriteRune(r)
default: