mirror of https://github.com/OpenTTD/OpenTTD
Fix #12123: Allow not emitting zero digits in certain cases in number formats
parent
5d2e6e4efa
commit
02a8263730
|
@ -3,8 +3,8 @@
|
|||
##isocode ko_KR
|
||||
##plural 11
|
||||
##textdir ltr
|
||||
##numberformat 0000경0000조0000억0000만0000
|
||||
##numberabbreviations 4=0000경0000조0000억0000만|8=0000경0000조0000억|12=0000경0000조|16=0000경
|
||||
##numberformat 0000경{NBSP}1000조{NBSP}1000억{NBSP}1000만1000
|
||||
##numberabbreviations 4=0000경{NBSP}1000조{NBSP}1000억{NBSP}1000만|8=0000경{NBSP}1000조{NBSP}1000억|12=0000경{NBSP}1000조|16=0000경
|
||||
##decimalsep .
|
||||
##winlangid 0x0412
|
||||
##grflangid 0x3a
|
||||
|
|
|
@ -109,13 +109,23 @@ extern std::unique_ptr<icu::Collator> _current_collator;
|
|||
|
||||
/** The number digits available in a uint64_t. */
|
||||
constexpr int DIGITS_IN_UINT64_T = 20;
|
||||
/** Container for the formatting of a single digit. */
|
||||
struct DigitFormat {
|
||||
enum EmitBehaviour {
|
||||
DEFAULT, ///< Only emit the digit when it's not zero, or there is a higher digit not zero.
|
||||
EMIT_WHEN_NOTHING_IS_EMITTED_YET, ///< Emit the digit when it's not zero, or there is a higher digit not zero, or no digit has been emitted yet.
|
||||
RESET_HIGHER_DIGIT, ///< Only emit the digit when it is not zero, and reset the 'there is a higher digit not zero'-flag.
|
||||
};
|
||||
std::string separator; ///< The string to write after the digit, when the digit is emitted.
|
||||
EmitBehaviour emit_behaviour; ///< The behaviour with respect to emitting the digit.
|
||||
};
|
||||
/**
|
||||
* Table with the text to place after each of the digits of a number. The text at index "20 - i" will be
|
||||
* inserted after the digit with value "10**i". So, for "normal" thousand separators, the strings at indices
|
||||
* 3, 6, 9, 12, 15 and 18 will be filled. For CJK the strings at indices 0, 4, 8, 12 and 16 will be filled.
|
||||
* @see ParseNumberFormatSeparators
|
||||
*/
|
||||
using NumberFormatSeparators = std::array<std::string, DIGITS_IN_UINT64_T>;
|
||||
using NumberFormatSeparators = std::array<DigitFormat, DIGITS_IN_UINT64_T>;
|
||||
/** Container for the power to abbreviation mapping for formatting short numbers. */
|
||||
struct NumberAbbreviation {
|
||||
NumberAbbreviation(int64_t threshold, NumberFormatSeparators &format) : threshold(threshold), format(format) {}
|
||||
|
|
|
@ -994,6 +994,15 @@ static std::string ReplaceNBSP(std::string string)
|
|||
return string;
|
||||
}
|
||||
|
||||
static DigitFormat::EmitBehaviour GetEmitBehaviour(char c)
|
||||
{
|
||||
switch (c) {
|
||||
case '0': return DigitFormat::DEFAULT;
|
||||
case '1': return DigitFormat::RESET_HIGHER_DIGIT;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the \c NumberFormatSeparators out of the given format string, with the expected number of digits.
|
||||
*
|
||||
|
@ -1008,7 +1017,7 @@ static std::string ReplaceNBSP(std::string string)
|
|||
* configured. The simplest solution is just defining what character to place between each of the digits, i.e what
|
||||
* characters separate each of the digits. These are the \c NumberFormatSeparators.
|
||||
*
|
||||
* To define these, you simply write a string of \c length zeros and then add any characters in between at the right
|
||||
* To define these, you simply write a string of \c length digits and then add any characters in between at the right
|
||||
* locations so the digit grouping is correct. When formatting numbers, it will start at the appropriate digit and
|
||||
* continue from there with separators.
|
||||
*
|
||||
|
@ -1021,22 +1030,26 @@ static std::string ReplaceNBSP(std::string string)
|
|||
*/
|
||||
std::optional<std::string> ParseNumberFormatSeparators(NumberFormatSeparators &separators, std::string_view format, size_t length)
|
||||
{
|
||||
static const std::string EXPECTED_DIGIT = "01";
|
||||
separators.fill({});
|
||||
size_t seen_zeros = 0;
|
||||
size_t seen_digits = 0;
|
||||
|
||||
auto it_separator = separators.rbegin();
|
||||
auto iter = format.find_last_of('0');
|
||||
auto iter = format.find_last_of(EXPECTED_DIGIT);
|
||||
while (iter != std::string_view::npos && it_separator != separators.rend()) {
|
||||
seen_zeros++;
|
||||
seen_digits++;
|
||||
|
||||
*it_separator = ReplaceNBSP(std::string(format.substr(iter + 1)));
|
||||
it_separator->emit_behaviour = GetEmitBehaviour(format[iter]);
|
||||
it_separator->separator = ReplaceNBSP(std::string(format.substr(iter + 1)));
|
||||
++it_separator;
|
||||
|
||||
format = format.substr(0, iter);
|
||||
iter = format.find_last_of('0');
|
||||
iter = format.find_last_of(EXPECTED_DIGIT);
|
||||
}
|
||||
|
||||
if (seen_zeros != length) return fmt::format("Unexpected number of digits ({} vs {}) in format string: [{}]", seen_zeros, length, format);
|
||||
/* Always emit the last digit when nothing is emitted. */
|
||||
separators.rbegin()->emit_behaviour = DigitFormat::EMIT_WHEN_NOTHING_IS_EMITTED_YET;
|
||||
if (seen_digits != length) return fmt::format("Unexpected number of digits ({} vs {}) in format string: [{}]", seen_digits, length, format);
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
|
|
@ -423,15 +423,20 @@ static void FormatNumber(StringBuilder &builder, int64_t number, const NumberFor
|
|||
uint64_t divisor = 10000000000000000000ULL;
|
||||
uint64_t num = number;
|
||||
uint64_t tot = 0;
|
||||
for (size_t i = 0; i < separators.size(); i++) {
|
||||
bool emitted = false;
|
||||
for (const DigitFormat &format : separators) {
|
||||
uint64_t quot = 0;
|
||||
if (num >= divisor) {
|
||||
quot = num / divisor;
|
||||
num = num % divisor;
|
||||
}
|
||||
if ((tot |= quot) != 0 || i == separators.size() - 1) {
|
||||
|
||||
if (format.emit_behaviour == DigitFormat::RESET_HIGHER_DIGIT) tot = 0;
|
||||
|
||||
if ((tot |= quot) != 0 || (format.emit_behaviour == DigitFormat::EMIT_WHEN_NOTHING_IS_EMITTED_YET && !emitted)) {
|
||||
builder += '0' + quot; // quot is a single digit
|
||||
builder += separators[i].data();
|
||||
builder += format.separator.data();
|
||||
emitted = true;
|
||||
}
|
||||
|
||||
divisor /= 10;
|
||||
|
|
Loading…
Reference in New Issue