fix: normalization of city name address
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// ErrNotFound is returned by providers when a callsign is unknown.
|
||||
@@ -100,6 +101,7 @@ func (m *Manager) Lookup(ctx context.Context, callsign string) (Result, error) {
|
||||
// corrected entity mapping (e.g. Sicily → Italy) heal stale cached
|
||||
// rows without waiting for the TTL to expire.
|
||||
fillFromDXCC(&r, dxcc)
|
||||
normalizeNames(&r)
|
||||
return r, nil
|
||||
}
|
||||
|
||||
@@ -111,6 +113,7 @@ func (m *Manager) Lookup(ctx context.Context, callsign string) (Result, error) {
|
||||
r.Source = p.Name()
|
||||
r.FetchedAt = time.Now().UTC()
|
||||
fillFromDXCC(&r, dxcc)
|
||||
normalizeNames(&r)
|
||||
_ = m.cache.Put(ctx, r)
|
||||
return r, nil
|
||||
}
|
||||
@@ -145,6 +148,43 @@ func (m *Manager) Lookup(ctx context.Context, callsign string) (Result, error) {
|
||||
return Result{}, lastErr
|
||||
}
|
||||
|
||||
// normalizeNames title-cases the human-readable text fields so a QRZ/HamQTH
|
||||
// reply in ALL CAPS ("NOEL CHENAVARD", "VETRAZ-MONTHOUX") is stored and shown
|
||||
// consistently ("Noel Chenavard", "Vetraz-Monthoux"). State/zones/grid are
|
||||
// left untouched (codes like CT must stay as-is).
|
||||
func normalizeNames(r *Result) {
|
||||
r.Name = titleCase(r.Name)
|
||||
r.QTH = titleCase(r.QTH)
|
||||
r.Address = titleCase(r.Address)
|
||||
}
|
||||
|
||||
// titleCase lowercases the whole string then capitalises the first letter of
|
||||
// each word. Word boundaries are any non-alphanumeric rune (space, hyphen,
|
||||
// apostrophe, slash…), so "vetraz-monthoux" → "Vetraz-Monthoux" and
|
||||
// "o'brien" → "O'Brien". Digits never get a leading capital ("74140" stays).
|
||||
func titleCase(s string) string {
|
||||
s = strings.TrimSpace(s)
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
runes := []rune(strings.ToLower(s))
|
||||
atWordStart := true
|
||||
for i, r := range runes {
|
||||
switch {
|
||||
case unicode.IsLetter(r):
|
||||
if atWordStart {
|
||||
runes[i] = unicode.ToUpper(r)
|
||||
}
|
||||
atWordStart = false
|
||||
case unicode.IsDigit(r):
|
||||
atWordStart = false
|
||||
default:
|
||||
atWordStart = true
|
||||
}
|
||||
}
|
||||
return string(runes)
|
||||
}
|
||||
|
||||
// fillFromDXCC fills (or overrides) country/continent/zones/lat/lon from
|
||||
// the cty.dat resolver. cty.dat is the authoritative source for DXCC
|
||||
// mapping, so Country/Continent/CQZ/ITUZ are ALWAYS overridden when it
|
||||
|
||||
Reference in New Issue
Block a user