numbers

package
v0.0.0-...-3579762 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 1, 2026 License: Apache-2.0 Imports: 7 Imported by: 0

Documentation

Overview

Package numbers verbalizes the numbers found in text as English words.

It is a standalone engine: unlike the name-oriented manglers it does its own number-aware scanning (it must see the decimal points and digit-group separators that the general tokenizer elides), so it does not depend on a separate tokenizer. The parent mangling package reaches it through GoMangler.ConstName.

Entry points

  • NumberMangler rewrites every number in a string ("level 0.25 here" → "level one quarter here"). See NumberMangler.NumberWords for the full rules, and NumberMangler.AppendWords for the allocation-free variant.
  • RuneNumber resolves a single Unicode numeral rune to its value ('½' → 0.5, 'Ⅶ' → 7).
  • Roman renders an integer as a lowercase roman numeral (6 → "vi"), handy for compact sequence labels.

How numbers are recognized

Integers become cardinals ("123" → "one hundred and twenty three"); a value in (-1, 1) matching a simple fraction becomes that fraction ("0.25" → "one quarter"); any other decimal is spelled digit-by-digit after "dot" ("3.14" → "three dot one four"); negatives are prefixed with "minus". Thousands separators (space, comma or underscore before exactly three digits) are reconstructed, and integers too large for int64 are spelled digit by digit so no input overflows.

Rendering honors the mangler options: WithNumberStripOne, WithNumberStripAnd, WithNumberDetectPrecision and WithSpecialNumbers.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NumberRune

func NumberRune(r rune) string

NumberRune is the default-options form of NumberMangler.NumberRune: it verbalizes a single Unicode numeral rune with no options applied. Build a NumberMangler and call its method when options matter.

func Roman

func Roman(n int64) string

Roman renders a positive integer as a lowercase roman numeral (e.g. 12 → "xii", 1994 → "mcmxciv").

It uses the standard subtractive notation (4 → "iv", not "iiii"; 9 → "ix", not "viiii"), which makes it a handy source of compact, human-readable sequence labels — nested loop indices, list markers, and the like: "i", "ii", "iii", "iv", "v", … Uppercase the result with strings.ToUpper if you need "IV".

It returns "" for n ≤ 0.

There is no upper bound: values above 3999 simply repeat "m" (4000 → "mmmm"), which is unambiguous if unconventional (we don't use the vinculum system for large numbers, as it requires non-ASCII characters).

func RuneNumber

func RuneNumber(r rune) (float64, bool)

RuneNumber returns the numeric value of a Unicode numeral rune (categories No and Nl — e.g. '½' → 0.5, 'Ⅶ' → 7, '②' → 2) and whether r is such a numeral.

Decimal digits (Nd) and CJK ideographic numbers (Lo) are deliberately excluded. It lets a numeral rune verbalize through this engine ('½' → "one half") and lets the asciify tier render it as a plain number ('½' → "0.5"). Table in numerals.go.

Types

type NumberMangler

type NumberMangler struct {
	// contains filtered or unexported fields
}

NumberMangler verbalizes the numbers found in text as English words: cardinals and common fractions, with digit-group (thousands) reconstruction.

It is a standalone engine: unlike the name-oriented manglers it does its own number-aware scanning (it must see decimal points and digit-group separators that the general tokenizer elides), so it does not depend on a separate tokenizer.

func MakeNumberMangler

func MakeNumberMangler(opts ...NumberOption) NumberMangler

MakeNumberMangler returns a value NumberMangler.

func NewNumberMangler

func NewNumberMangler(opts ...NumberOption) *NumberMangler

NewNumberMangler returns a pointer to a NumberMangler.

func (NumberMangler) AppendWords

func (m NumberMangler) AppendWords(dst []byte, in string) []byte

AppendWords appends the english-words form of in (numbers verbalized, surrounding text verbatim) to dst and returns the extended slice.

This is the string-free sibling of NumberMangler.NumberWords.

The caller owns dst and may reuse it across calls, so bulk verbalization runs allocation-free, like so:

var scratch []byte
for _, s := range inputs {
	scratch = m.AppendWords(scratch[:0], s)
	use(scratch) // valid until the next AppendWords into scratch
}

func (NumberMangler) NumberRune

func (m NumberMangler) NumberRune(r rune) string

NumberRune verbalizes a single Unicode numeral rune as English words ('½' → "one half", 'Ⅶ' → "seven", '②' → "two"), or returns "" when r is not a numeral rune (categories No and Nl; see RuneNumber).

It is the single-rune form of NumberMangler.NumberWords: it resolves the rune's value with RuneNumber and renders it directly, skipping the string scanner and the string(r) allocation that NumberWords(string(r)) would cost — this runs per numeral rune in the asciify pass.

Rendering honors the mangler's options (WithNumberStripOne etc.), so a numeral rune verbalizes consistently with the same value written as digits ('½' and "1/2"-style input agree under one mangler). Use the package-level NumberRune for a quick default-options rendering without a mangler.

func (NumberMangler) NumberWords

func (m NumberMangler) NumberWords(in string) string

NumberWords rewrites every number found in a string as english words.

It leaves the surrounding text untouched, e.g. "10 11" => "ten eleven", "level 0.25 here" => "level one quarter here".

Multiple numbers are handled independently.

Each number is an optional sign followed by digits with an optional decimal point:

  • integers become cardinals: "123" => "one hundred and twenty three";
  • a value in (-1, 1) matching a simple fraction becomes that fraction: "0.25" => "one quarter", "0.1" => "one tenth", "0.75" => "three quarters";
  • any other decimal is spelled digit-by-digit after "dot": "0.31456" => "zero dot three one four five six";
  • negatives are prefixed with "minus".

Thousands separators are reconstructed: within a number, a space, comma or underscore followed by exactly three digits joins the group, so "1 234", "1,234" and "1_234" all become "one thousand two hundred and thirty four", while "1 2" stays two numbers ("one two") and "1;234" is not joined (";" is not a separator).

Registered special numbers (WithSpecialNumbers) are matched (within tolerance) ahead of everything else, so "3.1415" => "pi".

Rendering honors the mangler's options: WithNumberStripOne ("one hundred" => "hundred", "one tenth" => "tenth"), WithNumberStripAnd (drops the "and"), and WithNumberDetectPrecision (fraction and special-number tolerance).

type NumberOption

type NumberOption func(numberOptions) numberOptions

NumberOption customizes the behavior of the NumberMangler.

func WithNumberDetectPrecision

func WithNumberDetectPrecision(precision uint) NumberOption

WithNumberDetectPrecision sets the number of decimal places used when matching a value against known fractions and special numbers.

A higher precision distinguishes closer values (e.g. 0.333 from 1/3) at the cost of fewer fuzzy matches.

func WithNumberStripAnd

func WithNumberStripAnd(strip bool) NumberOption

WithNumberStripAnd alters how NumberMangler.NumberWords renders numerals: whenever stripped the "and" in "one hundred and ten", etc is elided.

func WithNumberStripOne

func WithNumberStripOne(strip bool) NumberOption

WithNumberStripOne alters how NumberMangler.NumberWords renders numerals: whenever stripped the "one" prefix in "one hundred", "one tenth", etc is elided.

func WithSpecialNumbers

func WithSpecialNumbers(specials map[string]string) NumberOption

WithSpecialNumbers registers named numeric constants, matched (numerically, within the detection precision) ahead of cardinal/fraction rendering.

Example: WithSpecialNumbers(map[string]string{"3.1415": "pi", "2.718": "e"}) renders any number within tolerance of 3.1415 as "pi".

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL