feat(discovery/crawler): PLZ-to-land inference helper

This commit is contained in:
2026-04-18 11:54:17 +02:00
parent e359d06d13
commit 4694804331
2 changed files with 74 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
package crawler
import "strings"
// InferLand maps a PLZ to a DACH country. 5-digit -> DE. 4-digit is ambiguous
// between AT and CH; we recognize common CH ranges (1000-1299 Geneva/Vaud,
// 3000-3999 Bern, 4000-4999 Basel/Aarau, 6000-6999 Luzern/Ticino/Wallis,
// 8000-8999 Zurich, 9000-9999 St. Gallen) and fall back to AT for everything
// else 4-digit. Unknown -> "". The Land string is the form used throughout
// discovery (not ISO-2).
func InferLand(plz string) string {
plz = strings.TrimSpace(plz)
switch len(plz) {
case 5:
if !isAllDigits(plz) {
return ""
}
return "Deutschland"
case 4:
if !isAllDigits(plz) {
return ""
}
switch plz[0] {
case '1':
if plz >= "1200" && plz <= "1299" {
return "Schweiz"
}
return "Oesterreich"
case '3', '4', '6', '8', '9':
return "Schweiz"
default:
return "Oesterreich"
}
}
return ""
}
func isAllDigits(s string) bool {
for _, r := range s {
if r < '0' || r > '9' {
return false
}
}
return true
}

View File

@@ -0,0 +1,29 @@
package crawler
import "testing"
func TestInferLand(t *testing.T) {
tests := []struct {
name string
plz string
want string
}{
{"empty", "", ""},
{"de 5-digit", "49186", "Deutschland"},
{"de 5-digit low", "01067", "Deutschland"},
{"at 4-digit typical", "1010", "Oesterreich"},
{"ch 4-digit typical", "8001", "Schweiz"},
{"ch 4-digit zurich range", "8000", "Schweiz"},
{"ch 4-digit bern range", "3000", "Schweiz"},
{"at 4-digit outside ch ranges", "2500", "Oesterreich"},
{"short garbage", "12", ""},
{"non-numeric", "abcde", ""},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
if got := InferLand(tc.plz); got != tc.want {
t.Errorf("InferLand(%q) = %q; want %q", tc.plz, got, tc.want)
}
})
}
}