Transaction
AA050E43608D06…3A83C979A82F
Block 25,954 · index 1 · indexed
Summary
- Hash
- AA050E43608D066949DF1C4EB01347D52A9D02C242A7899B25C63A83C979A82F
- Block
- 25,954
- Size
- 5937 bytes
- Gas used
- 10,150,998 / 12,181,257
- Fee
- 1000000ugnot
- Memo
- gnopublish
- Status
- success
Messages
Arguments · 9
- #1soundex
- #2README.md
- #3# `gno.land/p/moul/x/daily/soundex/v0` **Soundex phonetic algorithm** — `Encode`, `Match`, `EncodeAll`, `Normalize`. Names that sound alike in English encode to the same four-character key: `Robert` and `Rupert` both give `R163`. ```go import "gno.land/p/moul/x/daily/soundex/v0" soundex.Encode("Robert") // "R163" soundex.Encode("Ashcraft") // "A261" soundex.Match("Robert", "Rupert") // true ``` The 1918 Russell/Odell algorithm as used by the US census, with the three rules that are usually got wrong implemented explicitly — each has a test: - **the first letter keeps its own code** and still suppresses a following consonant of the same code, so `Pfister` → `P236`, not `P123`; - **`h` and `w` are transparent**: consonants either side are treated as adjacent, so `Ashcraft` → `A261`, not `A226`; - **vowels are not transparent** — they separate, so a repeated code after a vowel is emitted again: `Tymczak` → `T522`. Non-letters are ignored, so `O'Brien` and `OBrien` agree. Input with no ASCII letters has **no key** (`""`), and `Match` never reports two such inputs as matching — "no name" is not a name they share. Soundex is English-centric and lossy *by design*: it is a **blocking key** for finding candidates cheaply, never proof that two names are the same. **Live demo:** [`r/moul/x/daily/soundexdemo`](https://github.com/moul/gno-contracts/tree/main/r/moul/x/daily/soundexdemo/v0) · render it at [`/r/moul/x/daily/soundexdemo/v0`](https://gno.land/r/moul/x/daily/soundexdemo/v0). <!-- BEGIN GNOCONTRACTS FOOTER (generated by `make readmes`; do not edit below) --> --- Part of **[moul/gno-contracts](https://github.com/moul/gno-contracts)** — moul's versioned gno.land contracts. See the repository for the full catalog, build/test tooling, and usage. > 🧪 **Highly experimental — potentially vibe-coded.** Not audited; may break, change, or be removed at any time. Do not use with anything of value. Full disclaimer: [DISCLAIMER](https://github.com/moul/gno-contracts/blob/main/DISCLAIMER.md). <!-- END GNOCONTRACTS FOOTER -->
- #4gnomod.toml
- #5module = "gno.land/p/moul/x/daily/soundex/v0" gno = "0.9"
- #6soundex.gno
- #7// Package soundex implements the Soundex phonetic algorithm as a pure, // reusable package: names that sound alike in English encode to the same // four-character key, so "Robert" and "Rupert" both give R163. // // This is the 1918 Russell/Odell algorithm as used by the US census, with the // rules that are usually got wrong implemented explicitly: // // - the first letter is kept as-is and its digit still suppresses a // following consonant of the same code ("Pfister" → P236, not P123); // - 'h' and 'w' are TRANSPARENT: consonants either side of them are treated // as adjacent ("Ashcraft" → A261, not A226); // - vowels are not transparent — they separate, so a repeated code after a // vowel is emitted again ("Tymczak" → T522). // // Soundex is English-centric and lossy by design: it is a *blocking* key for // finding candidates, never a proof that two names match. // // A live demo of this package is at // [r/moul/x/daily/soundexdemo](/r/moul/x/daily/soundexdemo/v0). package soundex import "strings" // code returns the Soundex digit for a letter, or 0 for vowels and h/w/y. func code(c byte) byte { switch c { case 'B', 'F', 'P', 'V': return '1' case 'C', 'G', 'J', 'K', 'Q', 'S', 'X', 'Z': return '2' case 'D', 'T': return '3' case 'L': return '4' case 'M', 'N': return '5' case 'R': return '6' } return 0 } // upper returns c upper-cased if it is an ASCII letter, else 0. func upper(c byte) byte { if c >= 'a' && c <= 'z' { c -= 32 } if c >= 'A' && c <= 'Z' { return c } return 0 } // Encode returns the four-character Soundex key for s, or "" when s contains // no ASCII letters. Non-letters are ignored, so "O'Brien" and "OBrien" agree. func Encode(s string) string { // keep letters only letters := make([]byte, 0, len(s)) for i := 0; i < len(s); i++ { if c := upper(s[i]); c != 0 { letters = append(letters, c) } } if len(letters) == 0 { return "" } out := []byte{letters[0]} prev := code(letters[0]) // the first letter's own code still suppresses for i := 1; i < len(letters) && len(out) < 4; i++ { c := letters[i] d := code(c) switch { case d == 0: // 'h' and 'w' are transparent: leave prev alone so the consonants // either side are treated as adjacent. Vowels (and 'y') separate, // so they reset prev and allow the same code to repeat. if c != 'H' && c != 'W' { prev = 0 } case d != prev: out = append(out, d) prev = d default: // same code as the previous consonant, and not separated by a // vowel: collapsed. } } for len(out) < 4 { out = append(out, '0') } return string(out) } // Match reports whether two strings share a Soundex key. Empty keys never // match, so two inputs with no letters are not "the same name". func Match(a, b string) bool { ka, kb := Encode(a), Encode(b) return ka != "" && ka == kb } // EncodeAll returns the keys for each input, in order. func EncodeAll(names []string) []string { out := make([]string, 0, len(names)) for _, n := range names { out = append(out, Encode(n)) } return out } // Normalize upper-cases and strips non-letters — the input Encode actually // sees. Exposed so callers can show their work. func Normalize(s string) string { var b strings.Builder for i := 0; i < len(s); i++ { if c := upper(s[i]); c != 0 { b.WriteByte(c) } } return b.String() }
- #8/gno.MemPackageType
- #9 MPUserProd
Result log
msg:0,success:true,log:,events:[]