NAME
Locale::Unicode::RBNF::Substitution - Substitutions of a rule-based number format rule
VERSION
v0.1.0
DESCRIPTION
Internal module. This is a port of ICU4C NFSubstitution and its subclasses SameValueSubstitution, MultiplierSubstitution, ModulusSubstitution, IntegralPartSubstitution, FractionalPartSubstitution, AbsoluteValueSubstitution and NumeratorSubstitution (nfsubs.cpp, ICU 79.1).
CONVENTIONS
The methods follow the ICU code they are ported from, and share these arguments:
$stA scalar reference that receives an error status, the equivalent of ICU
UErrorCode. It holds a message starting with the ICU error code name, such asU_PARSE_ERROR: .... Most methods do nothing if it is already set.$outA scalar reference to the string being built by formatting.
$posThe position in
$outwhere the text produced is inserted. Rules are formatted by inserting their text into the output, then the text of their substitutions at their own offsets.$rcThe recursion count, checked against
$Locale::Unicode::RBNF::RuleSet::RECURSION_LIMIT(64), as ICU does, to stop runaway rule descriptions.$ppA parse position, as an hash reference with the keys
indexanderror, the equivalent of ICUParsePosition.$maskThe bit mask of the non-numerical rules already executed during a parse, used by ICU to prevent infinite recursion through them.
CLASSES
A substitution is the part of a rule text between two tokens, such as <<, >%%frac> or =#,##0=, which formats a value derived from the number, either with a rule set or with a Locale::Unicode::RBNF::DecimalFormat. The token character and the type of the rule decide the class used, as ICU NFSubstitution::makeSubstitution() does:
"Locale::Unicode::RBNF::Substitution::SameValue", for
==: the number itself."Locale::Unicode::RBNF::Substitution::Multiplier", for
<<in a normal rule: the number divided by the divisor of the rule."Locale::Unicode::RBNF::Substitution::Modulus", for
>>in a normal rule: the remainder of the division by the divisor of the rule.>>>uses the preceding rule directly."Locale::Unicode::RBNF::Substitution::IntegralPart", for
<<in a fraction rule: the integral part of the number."Locale::Unicode::RBNF::Substitution::FractionalPart", for
>>in a fraction rule: the fractional part, digit by digit, or with a fraction rule set."Locale::Unicode::RBNF::Substitution::AbsoluteValue", for
>>in a negative-number rule: the absolute value."Locale::Unicode::RBNF::Substitution::Numerator", for
<<in a fraction rule set: the numerator of the fraction whose denominator is the base value of the rule.
All classes inherit from Locale::Unicode::RBNF::Substitution, and override some of its methods, documented below for each class.
CONSTANTS
The rule types needed to choose the class of a substitution, duplicated from Locale::Unicode::RBNF::Rule to avoid a circular use: NEGATIVE_NUMBER (-1), IMPROPER_FRACTION (-2), PROPER_FRACTION (-3) and DEFAULT_RULE (-4).
The variable $DBL_MAX holds the largest double, and $MAX_INT64_IN_DOUBLE the largest integer a double holds exactly, 2^53 - 1.
CONSTRUCTORS
make
my $sub = Locale::Unicode::RBNF::Substitution->make( $pos, $rule, $predecessor, $rule_set, $formatter, $token, \$st );
This is ICU NFSubstitution::makeSubstitution(): it creates the substitution of the class matching the first character of the token and the type of the rule $rule, as described in "CLASSES", at the offset $pos of the rule text. $rule_set is the rule set owning the rule, $predecessor the preceding rule, used by >>>, and $formatter the Locale::Unicode::RBNF object, whose default rule set a numerator substitution uses.
It returns the substitution, or an empty list if the token is empty or an error occurred, in which case $st is set.
new
my $sub = Locale::Unicode::RBNF::Substitution::SameValue->new( $pos, $rule_set, $token, \$st );
This is the constructor of ICU NFSubstitution, shared by all classes. The token must begin and end with the same character. What is between them selects how the value is formatted: nothing, or > for >>>, means the rule set owning the rule, a name starting with % another rule set of the formatter, and a pattern starting with # or 0 a Locale::Unicode::RBNF::DecimalFormat.
Rule sets reference one another through substitutions, so the rule set is kept as a weak reference.
METHODS
calc_upper_bound
my $bound = $sub->calc_upper_bound( $old_upper_bound );
Returns the upper bound of the values the substitution can match during a parse. The base implementation returns the bound given.
compose_rule_value
my $value = $sub->compose_rule_value( $new, $old );
Combines the value parsed by the substitution, $new, with the value of the rule, $old. The base implementation returns $new.
do_parse
my( $success, $value ) = $sub->do_parse( $text, $pp, $base_value, $upper_bound, $lenient, $mask, $rc );
This is ICU NFSubstitution::doParse(): it parses the text with the rule set, or the decimal format, of the substitution, then composes the result with the base value given, with "compose_rule_value". It returns a list of 2 elements: whether something was matched, and the value.
This method is provided by Locale::Unicode::RBNF::PP, and used by the pure Perl parsing engine. The classes Modulus, FractionalPart and Numerator have their own version.
do_substitution_double
$sub->do_substitution_double( $number, $out, $pos, $rc, $st );
Transforms the number with "transform_double", then formats the result into $out, at $pos plus the offset of the substitution: with the rule set, in integer space if the result is an integer, or with the decimal format. An infinite result is formatted with the infinity rule of the rule set.
do_substitution_int
$sub->do_substitution_int( $number, $out, $pos, $rc, $st );
The same as "do_substitution_double", for an integer, transformed with "transform_int". Beyond 2^53, a decimal format formats the integer itself, rather than a double, so that its precision is kept.
get_pos
Returns the offset of the substitution in the rule text.
get_rule_set
Returns the rule set used by the substitution, or undef if it uses a decimal format.
is_modulus
Returns true for a modulus substitution, and false otherwise.
set_decimal_format_symbols
$sub->set_decimal_format_symbols( $symbols, \$st );
Passes new decimal format symbols to the decimal format of the substitution, if it has one.
set_divisor
$sub->set_divisor( $radix, $exponent, \$st );
Does nothing, except for multiplier and modulus substitutions.
to_string
Returns the token of the substitution in the ICU syntax, such as <%spellout-cardinal< or =#,##0=, built with "token_char".
token_char
Returns the character delimiting the token of the substitution: =, < or >. Each class defines it.
transform_double
my $n = $sub->transform_double( $number );
Returns the value derived from a double that the substitution formats. The base implementation returns the number unchanged.
transform_int
my $n = $sub->transform_int( $number );
Returns the value derived from an integer that the substitution formats. The base implementation returns the number unchanged.
Locale::Unicode::RBNF::Substitution::SameValue
The == substitution: the value is passed through unchanged.
new
The same as the base "new", except that == alone, without a rule set or a decimal format, is an error.
calc_upper_bound
Returns the bound given.
compose_rule_value
Returns the value parsed, $new.
token_char
Returns =.
transform_double
Returns the number unchanged.
transform_int
Returns the number unchanged.
Locale::Unicode::RBNF::Substitution::Multiplier
The << substitution of a normal rule: the number is divided by the divisor of the rule, and the quotient is formatted.
new
my $sub = Locale::Unicode::RBNF::Substitution::Multiplier->new( $pos, $rule, $rule_set, $token, \$st );
The same as the base "new", with the owning rule, from which the divisor is taken, as an additional argument. A divisor of 0 is an error.
calc_upper_bound
Returns the divisor.
compose_rule_value
Returns the value parsed, $new, multiplied by the divisor.
set_divisor
$sub->set_divisor( $radix, $exponent, \$st );
Sets the divisor to the radix raised to the power of the exponent, as an int64_t. A divisor of 0 is an error.
token_char
Returns <.
transform_double
Returns the number divided by the divisor, floored. The quotient is not floored when it is formatted with a decimal format, the owning rule has no modulus substitution, and the rounding mode of the formatter is not floor, so that the decimal format can round it.
transform_int
Returns the number divided by the divisor, truncated towards zero.
Locale::Unicode::RBNF::Substitution::Modulus
The >> substitution of a normal rule: the remainder of the division of the number by the divisor of the rule is formatted. With >>>, the preceding rule is used directly, rather than the rule set.
new
my $sub = Locale::Unicode::RBNF::Substitution::Modulus->new( $pos, $rule, $predecessor, $rule_set, $token, \$st );
The same as the base "new", with the owning rule, from which the divisor is taken, and the preceding rule, used for >>>, as additional arguments. A divisor of 0 is an error.
calc_upper_bound
Returns the divisor.
compose_rule_value
Returns the value of the rule, $old, less its remainder by the divisor, plus the value parsed, $new.
do_parse
The same as the base "do_parse", except that, with >>>, the text is parsed with the preceding rule directly. This method is provided by Locale::Unicode::RBNF::PP.
do_substitution_double
The same as the base "do_substitution_double", except that, with >>>, the remainder is formatted with the preceding rule directly.
do_substitution_int
The same as the base "do_substitution_int", except that, with >>>, the remainder is formatted with the preceding rule directly.
is_modulus
Returns true.
set_divisor
$sub->set_divisor( $radix, $exponent, \$st );
Sets the divisor to the radix raised to the power of the exponent, as an int64_t. A divisor of 0 is an error.
to_string
Returns >>> if the preceding rule is used directly, and otherwise the same as the base "to_string".
token_char
Returns >.
transform_double
Returns the remainder of the division of the number by the divisor, as fmod() does.
transform_int
Returns the remainder of the division of the number by the divisor, with the sign of the number, as in C.
Locale::Unicode::RBNF::Substitution::IntegralPart
The << substitution of a fraction rule: the integral part of the number is formatted.
calc_upper_bound
Returns the largest double, since the integral part has no upper bound.
compose_rule_value
Returns the sum of the value parsed and of the value of the rule.
token_char
Returns <.
transform_double
Returns the number floored.
transform_int
Returns the number unchanged.
Locale::Unicode::RBNF::Substitution::FractionalPart
The >> substitution of a fraction rule: the fractional part of the number is formatted, either digit by digit with the rule set owning the rule, for >> and >>>, or with a fraction rule set, such as with >%%frac>.
new
The same as the base "new". With >>, >>>, or the rule set owning the rule, the digits are formatted one by one, separated with a space except for >>>. Otherwise, the rule set given becomes a fraction rule set, with "make_into_fraction_rule_set" in Locale::Unicode::RBNF::RuleSet.
calc_upper_bound
Returns 0, which is not used.
compose_rule_value
Returns the sum of the value parsed and of the value of the rule.
do_parse
When the digits are formatted one by one, the text is parsed one digit at a time with the rule set, with an upper bound of 10, until the text no longer matches. Otherwise, this is the same as the base "do_parse". This method is provided by Locale::Unicode::RBNF::PP.
do_substitution_double
When the digits are formatted one by one, each digit of the fractional part, including the zeros after the decimal point, is formatted as an integer with the rule set, from the shortest decimal representation of the number rounded to 20 fraction digits; if there is none, 0 is formatted, so that the result does not end with the word for the decimal point. Otherwise, this is the same as the base "do_substitution_double".
do_substitution_int
Does nothing, as a fractional part substitution has nothing to format for an integer.
token_char
Returns >.
transform_double
Returns the fractional part of the number.
transform_int
Returns 0.
Locale::Unicode::RBNF::Substitution::AbsoluteValue
The >> substitution of a negative-number rule: the absolute value of the number is formatted.
calc_upper_bound
Returns the largest double.
compose_rule_value
Returns the opposite of the value parsed.
token_char
Returns >.
transform_double
Returns the absolute value of the number.
transform_int
Returns the absolute value of the number.
Locale::Unicode::RBNF::Substitution::Numerator
The << substitution of a rule in a fraction rule set: the numerator of the fraction whose denominator is the base value of the rule is formatted, with the default rule set of the formatter. When the token ends with <<, such as in <%%digits<<, the leading zeros of the decimal expansion are formatted too.
new
my $sub = Locale::Unicode::RBNF::Substitution::Numerator->new( $pos, $denominator, $rule_set, $token, \$st );
The same as the base "new", with the denominator as an additional argument, and the default rule set of the formatter as the rule set. Without a rule set, this is an error.
calc_upper_bound
Returns the denominator.
compose_rule_value
Returns the value parsed divided by the value of the rule. As in C++, a division by 0 yields an infinity, or NaN for 0 divided by 0.
do_parse
The same as the base "do_parse", without lenient matching, which does not suit the algorithm, and, with leading zeros, counting the zeros parsed first. This method is provided by Locale::Unicode::RBNF::PP.
do_substitution_double
Formats the numerator, preceded by the leading zeros when they are requested, each zero preceded by a space.
do_substitution_int
Does nothing, as a numerator substitution has nothing to format for an integer.
token_char
Returns <.
transform_double
Returns the number multiplied by the denominator, rounded to the nearest integer.
transform_int
Returns the number multiplied by the denominator.
SEE ALSO
Locale::Unicode::RBNF, Locale::Unicode::RBNF::Rule, Locale::Unicode::RBNF::RuleSet
AUTHOR
Jacques Deguest <jack@deguest.jp>
COPYRIGHT & LICENSE
Copyright(c) 2026 DEGUEST Pte. Ltd.
Portions are derived from ICU, Copyright (C) 2016 and later Unicode, Inc. and others, under the Unicode License (https://www.unicode.org/copyright.html). Its text is in the LICENSE-UNICODE file of this distribution.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.