Table of contents
Part of nurago, a collection of independent Go packages for backend services.
import "github.com/tecnickcom/nurago/pkg/phonekeypad"
Turns 1-800-FLOWERS into 18003569377, following the ITU E.161 keypad layout.
+-----+-----+-----+
| 1 | 2 | 3 |
| | ABC | DEF |
+-----+-----+-----+
| 4 | 5 | 6 |
| GHI | JKL | MNO |
+-----+-----+-----+
| 7 | 8 | 9 |
| PQRS| TUV | WXYZ|
+-----+-----+-----+
| | 0 | |
+-----+-----+-----+
Why this is a package and not four lines
The mapping is trivial. The edge cases are where inline implementations diverge from each other.
The layout itself has a detail people get wrong from memory: 7 carries four letters (PQRS) and 9 carries four (WXYZ), while every other lettered key carries three. Q and Z were absent from older keypads entirely, and hand-written mappings still occasionally skip them.
Then there is what to do with everything that is not a letter or a digit. A vanity number arrives as 1-800-FLOWERS, or (800) FLOWERS, or 1.800.FLOWERS. KeypadNumber and KeypadNumberString drop unmapped runes rather than rejecting the input, so both accept what a person typed without pre-cleaning.
Two output shapes, and the counter-intuitive cost
phonekeypad.KeypadNumberString("1-800-FLOWERS") // "18003569377"
phonekeypad.KeypadNumber("1-800-FLOWERS") // []int{1,8,0,0,3,5,6,9,3,7,7}
phonekeypad.KeypadDigit('F') // 3, true
| Function | ns/op | B/op | allocs/op |
|---|---|---|---|
KeypadDigit | 1.30 | 0 | 0 |
KeypadNumberString | 106 | 32 | 1 |
KeypadNumber | 167 | 240 | 1 |
Measured with go test -bench on Go 1.27.1, linux/amd64, Intel Core i7-1260P. Run go test -bench=. ./pkg/phonekeypad/ to reproduce them on your own hardware; the absolute values will differ, the ratios much less so.
The slice version is the slower and much heavier of the two, at 240 bytes against 32 for the same input. An []int on a 64-bit build spends eight bytes per digit where the string spends one. If you are going to join the digits into a string anyway, call KeypadNumberString and skip the intermediate slice; reach for KeypadNumber when you genuinely need the digits as numbers, such as when feeding them into a numtrie lookup.
KeypadDigit at 1.3 ns and zero allocations is a table lookup with no branching, cheap enough to call per rune in a loop of your own.
The lookup direction it does not do
This maps letters to digits. It does not map digits back to candidate words, because that direction is not a function: 3569377 matches FLOWERS and a large number of other strings, and resolving it needs a dictionary. Indexing vanity numbers for search is the usual reason people want the reverse, and the way to do it is to store the digit form produced here as the index key, then match on that.
Example
fmt.Println(phonekeypad.KeypadNumberString("1-800-FLOWERS"))
// Output:
// 18003569377
Full source is in example_phonekeypad_test.go. More runnable examples are on pkg.go.dev.
Dependencies
This package reaches no external module: it uses only the Go standard library.
Links
- Reference documentation
- Source code
- Prefix matching on digits: numtrie
- Number metadata: countryphone
- All nurago packages