The grammar of a number, read from the tokens of
Localize.Number.Lexer with a Localize.Number.Lexicon.t/0.
A number is read once with each of the lexicon's readings, the separator sets it may be written with, and is the value every valid reading gives. Where two readings give different values the text is refused as ambiguous rather than one guessed.
Grammar
number = lead, body, trail ;
lead = spaces, [ sign ], spaces, [ "(" ], spaces, [ sign ], spaces ;
trail = spaces, [ sign ], spaces, [ ")" ], spaces, [ sign ], spaces ;
body = integer, [ decimal, fraction ], [ exponent ] ;
integer = digits, { group, digits } ;
fraction = digits | zero-dash ;
zero-dash = dash, [ dash ] ;
exponent = ( "e" | "E" ), [ sign ], digits ;decimal and group are the marks of the reading in hand, and a
space is a group where the reading groups with one. The sign and
the parentheses are read from the two ends; the body between them
is walked once (body_number/4), building the string Elixir parses
and gathering what the rules need, which are checked at the end.
The rules a number must also satisfy are the named functions below,
each with the TR35 passage or decision it comes from:
one sign at most, before or after the digits, or parentheses, which make the number negative (
signed_body/2);no minus before a bare decimal mark, since "-.5" may be a zero written as a dash (
dash_for_zero?/4);a zero fraction written as one or two dashes, leniently only (
zero_fraction/3);no space inside the number unless the reading groups with one (
interior_space/2);no group separator in the fraction (
fraction_part/4);groups of the sizes the grouping mode allows (
integer_grouping/3);no period that is foreign to every reading, unless it is one decimal point between digits and not a thousands group (
no_stray_period/3);Elixir's digit separator
_only between two digits (the underscore clauses ofinteger_part/4andfraction_part/4).
Summary
Functions
Reads a number from a string with a lexicon.
Reads a number from the tokens of a string, already read by
Localize.Number.Lexer.tokens/2 with the same lexicon.
Types
Functions
@spec read(String.t(), Localize.Number.Lexicon.t(), Keyword.t()) :: {:ok, number() | Decimal.t()} | {:error, Exception.t()}
Reads a number from a string with a lexicon.
Arguments
stringis the text to read.lexiconis theLocalize.Number.Lexicon.t/0to read it with.optionsis a keyword list of options.
Options
:numberis the type to read::integer,:float,:decimal, ornilto read an integer where the text is one and a float otherwise.:groupingis how group separators are checked::lenient,:strictor:sizes.:max_decimal_exponentbounds the exponent of a decimal read.
Returns
{:ok, number}, or{:error, %Localize.InvalidValueError{}}when the text is not a number of the lexicon's locale, or{:error, %Localize.ParseError{reason: :unexpected_input}}when two readings give different numbers.
Examples
iex> {:ok, de} = Localize.validate_locale(:de)
iex> {:ok, lexicon} = Localize.Number.Lexicon.fetch(de, :latn, [])
iex> Localize.Number.Grammar.read("1.234,5", lexicon, number: :decimal, grouping: :lenient)
{:ok, Decimal.new("1234.5")}
@spec read_tokens( [Localize.Number.Lexer.token()], String.t(), Localize.Number.Lexicon.t(), Keyword.t() ) :: {:ok, number() | Decimal.t()} | {:error, Exception.t()}
Reads a number from the tokens of a string, already read by
Localize.Number.Lexer.tokens/2 with the same lexicon.
Localize.Number.Scanner reads a whole string into tokens once and
hands each run with the shape of a number here, so that no run is
read twice.
Arguments
tokensare the tokens ofstring.stringis the text the tokens were read from, which an error names.lexiconis theLocalize.Number.Lexicon.t/0the tokens were read with.optionsare the options ofread/3.
Returns
{:ok, number}, or{:error, %Localize.InvalidValueError{}}when the text is not a number of the lexicon's locale, or{:error, %Localize.ParseError{reason: :unexpected_input}}when two readings give different numbers.
Examples
iex> {:ok, en} = Localize.validate_locale(:en)
iex> {:ok, lexicon} = Localize.Number.Lexicon.fetch(en, :latn, [])
iex> tokens = Localize.Number.Lexer.tokens("1,234.5", lexicon)
iex> Localize.Number.Grammar.read_tokens(tokens, "1,234.5", lexicon, [])
{:ok, 1234.5}