Keep every legal compound surname reachable, and tighten the README wording

This commit is contained in:
Mikael Göransson
2026-08-27 23:49:53 +02:00
committed by lilleman-tw
parent cd25aea6f1
commit e73cb398ac
4 changed files with 21 additions and 14 deletions
+7 -6
View File
@@ -17,7 +17,9 @@ lacked the locale coverage and format control we needed.
id), never for what character classes and choices already do.
- **Composable** — templates nest without limit: weighted choices, character
classes and sub-templates combine to model any format.
- **Reproducible** — seed a faker and it emits the same sequence every time.
- **Reproducible** — seed a faker and it emits the same sequence every time, for a
given version of the data: changing how a value is composed shifts the stream for
that value and for everything drawn after it in the same faker.
Every built-in draws only from that seed — no wall-clock, no `crypto/rand`
so determinism holds end to end.
- **Zero dependencies** — standard library only.
@@ -337,11 +339,10 @@ rejected at `New`.
may be a `{..path}` reference too (`{name|..en_US.person}`).
Inside a `format`, `0 1 A a` are **always** character classes — so a fixed digit
or letter must be escaped (`#1`, `#A`) or it becomes random. Only those four
characters are classes: digits `2``9` and every other letter are literal. A
format of `100 Main St` renders e.g. `506 Mdin St` — the `1`, `0`, `0` and `a`
were random, the `M`, `in` and `St` were not. A half-fixed string is the trap:
`555-0100` keeps `555-` and randomises the last four digits. For a value with no
or letter must be escaped (`#1`, `#A`) or it becomes random. A format of
`100 Main St` renders e.g. `506 Mdin St` — the `1`, `0`, `0` and `a` were random,
the `M`, `in` and `St` were not. A half-fixed string is the trap: `555-0000`
keeps `555-` and randomises the last four digits. For a value with no
tokens at all, use a bare string node (`"100 Main St"`), emitted verbatim.
**Putting it together** (`person.json`):
+9 -3
View File
@@ -17,9 +17,15 @@
},
{
"format": "{first}{last}",
"weight": 0.4,
"first": ["Hell", "Norr", "Wall"],
"last": ["berg", "blad", "crona", "dahl", "ed", "fors", "gren", "holm", "in", "kvist", "man", "mark", "qvist", "stedt", "sten", "strand", "ström", "vall"]
"weight": 0.267,
"first": ["Hell", "Wall"],
"last": ["berg", "blad", "crona", "dahl", "ed", "fors", "gren", "holm", "in", "kvist", "man", "mark", "qvist", "roth", "stedt", "sten", "strand", "ström", "vall"]
},
{
"format": "{first}{last}",
"weight": 0.133,
"first": ["Norr"],
"last": ["berg", "blad", "crona", "dahl", "ed", "fors", "gren", "holm", "in", "kvist", "löf", "lund", "man", "mark", "qvist", "stedt", "sten", "strand", "ström", "vall"]
},
["Berg", "Blom", "Eismar", "Falk", "Holm", "Lind", "Norberg", "Strand", "Ström", "von Flemming", "Åberg", "Öberg"]
],
+3 -4
View File
@@ -127,10 +127,9 @@ func TestShippedMiscReferenceData(t *testing.T) {
}
}
// TestSwedishNamesHaveNoTripleLetter pins an orthographic rule the shape regexes
// miss: Swedish never triples a consonant, so no prefix/suffix pair in the name
// data may compose one (Jöns+sson, Wall+lund, Norr+roth).
func TestSwedishNamesHaveNoTripleLetter(t *testing.T) {
// TestSwedishPersonNamesHaveNoTripleLetter pins an orthographic rule the shape
// regexes miss: Swedish never triples a consonant.
func TestSwedishPersonNamesHaveNoTripleLetter(t *testing.T) {
f := newFakes(t, "data/sv_SE", WithSeed(11))
for _, path := range []string{"person", "person.last"} {
for i := 0; i < 20000; i++ {
+2 -1
View File
@@ -231,7 +231,8 @@ func TestShippedStreetComposition(t *testing.T) {
}
func TestShippedLastNameComposition(t *testing.T) {
// last is a choice of patronymic {first}sson templates and literal surnames.
// last is a choice of patronymic {first}sson templates, compound
// {first}{last} templates and literal surnames.
f := newFakes(t, "data/sv_SE", WithSeed(6))
for i := 0; i < 300; i++ {
if s := fake(t, f, "person.last"); !swedishName.MatchString(s) {