1// Package soundexdemo is a small gnoweb demo of the Soundex phonetic algorithm2// provided by the [p/moul/x/daily/soundex](/p/moul/x/daily/soundex/v0) library:3// it groups a small name list by phonetic key so the "sounds alike" clusters4// are visible.5//6// It contains no phonetic logic of its own. Stateless, so Render is7// deterministic — names are grouped in first-seen order, never by iterating a8// map.9package soundexdemo1011import (12 "strings"1314 "gno.land/p/moul/x/daily/soundex/v0"15)1617// names include several deliberate near-collisions.18var names = []string{19 "Robert", "Rupert", "Rubin",20 "Ashcraft", "Ashcroft",21 "Tymczak", "Pfister", "Honeyman",22}2324// Render renders the demo for gnoweb.25//26// Render("") / Render("/") -> the name table + clusters27// Render("/<name>") -> that name's key28func Render(path string) string {29 var b strings.Builder30 b.WriteString("# Soundex\n\n")31 b.WriteString("Phonetic keys for English names, demoing the ")32 b.WriteString("[`p/moul/x/daily/soundex`](/p/moul/x/daily/soundex/v0) library.\n\n")3334 if q := parseArg(path); q != "" {35 k := soundex.Encode(q)36 b.WriteString("## `")37 b.WriteString(q)38 b.WriteString("`\n\n")39 if k == "" {40 b.WriteString("_No ASCII letters — no key._\n")41 } else {42 b.WriteString("key: **")43 b.WriteString(k)44 b.WriteString("** (normalized: `")45 b.WriteString(soundex.Normalize(q))46 b.WriteString("`)\n")47 }48 return b.String()49 }5051 b.WriteString("| name | key |\n|---|---|\n")52 for _, n := range names {53 b.WriteString("| ")54 b.WriteString(n)55 b.WriteString(" | `")56 b.WriteString(soundex.Encode(n))57 b.WriteString("` |\n")58 }5960 // group by key, preserving first-seen order (never iterate a map)61 b.WriteString("\n## Sounds alike\n\n")62 keys := []string{}63 byKey := map[string][]string{}64 for _, n := range names {65 k := soundex.Encode(n)66 if _, seen := byKey[k]; !seen {67 keys = append(keys, k)68 }69 byKey[k] = append(byKey[k], n)70 }71 for _, k := range keys {72 if len(byKey[k]) < 2 {73 continue74 }75 b.WriteString("- **")76 b.WriteString(k)77 b.WriteString("**: ")78 b.WriteString(strings.Join(byKey[k], ", "))79 b.WriteString("\n")80 }8182 b.WriteString("\n> A *blocking* key for finding candidates, never proof that two names match.\n")83 return b.String()84}8586func parseArg(path string) string {87 s := strings.TrimSpace(path)88 s = strings.TrimPrefix(s, "/")89 if i := strings.IndexByte(s, '/'); i >= 0 {90 s = s[:i]91 }92 return s93}94Render(path string) string
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.