Я пытаюсь исправить ошибку форматирования в классе PHP NumberFormatter для моего языка, болгарского: группировка тысяч вводится только для чисел, состоящих из 5+ цифр, т. е. «5 000» неверно.
Есть ли предопределенная константа, которую я могу использовать?
Я думал, что это будет NumberFormatter::GROUPING_SIZE, но это не учитывает вышеуказанное правило. Должен ли я искать какой-то другой атрибут или то, что я пытаюсь сделать, невозможно?
@CBroe, спасибо! Возможно, для меня это слишком сложно, но я попробую. Однако я заметил, что в приведенном вами описании примера упоминаются grouping_size и secondary_grouping_size. Могут ли они быть тем, что мне нужно? В документации страницы PHP ничего не упоминается об их значении, что очень бесполезно.
Только что провел пару тестов, используя $num->setAttribute(NumberFormatter::GROUPING_SIZE, 4); и $num->setAttribute(NumberFormatter::SECONDARY_GROUPING_SIZE, 3);, но результаты не те, которые мне нужны, например. число 2,806,766 отображается как 280 6766. Я также пробовал переключать значения, но результаты все равно не имеют смысла.
Начнем с того, что это просто размеры групп, но они не указывают, какой разделитель ставится между группами. Поскольку вам по сути нужны разные разделители между вашими группами, это не поможет.
Я понимаю. Ну, я попробовал прочитать про DecimalFormat, но не смог понять, как создать свой собственный узор, поэтому просто оставлю этот вопрос.
группировка по тысячам вводится только для чисел, состоящих из 5+ цифр, т.е. "5 000" неверно" - а, так это значит, что для более длинного числа перед последними тремя цифрами будет пробел? 1 234 567 890 тогда было бы правильно? Я думаю, что это невозможно сделать даже с помощью средства форматирования шаблонов - потому что вам придется применить другой шаблон в зависимости от величины числа.
К сожалению, это будет невозможно с SECONDARY_GROUPING_SIZE, поскольку этот параметр ВО ВСЕХ СЛУЧАЯХ применяется к группам, расположенным дальше первой. $a = new \NumberFormatter("bg-BG", \NumberFormatter::DECIMAL); $a->setAttribute(NumberFormatter::GROUPING_SIZE, 4); $a->setAttribute(NumberFormatter::SECONDARY_GROUPING_SIZE, 3); echo $a->format(10005000) произведет 1 000 5000.
@CBroe, верно. Болгарский язык – и я думаю, русский, чешский и т. д. – вводит разделитель тысяч только для чисел, состоящих из 5+ цифр. Итак, 5 000 неправильно, но 1 200 500 правильно. Я надеялся, что в последних версиях (8.x) разработчики PHP обратят внимание на этот факт.
Фактическая функциональность, лежащая в основе этого, не реализована самими разработчиками PHP, насколько я знаю, они просто предоставляют «оболочку» PHP, которая передает это в некоторую библиотеку C/C++ - так что это не совсем их дело.
Ранее вы задавали аналогичный вопрос. Если это действительно отдельные проблемы, это нормально, но если они связаны и могут быть объединены в один единый вопрос, это, вероятно, будет лучше.
@ChrisHaas, это похоже только в той степени, в которой проблема вызвана классом NumberFormatter. Я почти уверен, что если бы я написал о двух отдельных проблемах, требующих отдельного решения, в одной теме, вопрос был бы закрыт.






Хотя это вряд ли удастся сделать напрямую, вы можете использовать класс-оболочку, который изменяет выходные данные в соответствии с вашими ожиданиями:
class BulgarianNumberFormatter extends \NumberFormatter
{
public function __construct(
string|null $locale = 'bg_BG',
int $style = null,
string $pattern = null
) {
parent::__construct($locale, $style, $pattern);
}
public function format(
int|float $num,
int $type = self::TYPE_DEFAULT
): string|false {
$numOfWholeDigits = $num != 0 ? floor(log10($num) + 1) : 1;
$formatted = parent::format($num, $type);
if ($numOfWholeDigits < 6) {
$formatted = str_replace(
$this->getSymbol(static::GROUPING_SEPARATOR_SYMBOL),
'',
$formatted
);
}
return $formatted;
}
}
Использовать:
require_once('/path/to/BulgarianNumberFormatter.php');
// or
use Namespace\Of\BulgarianNumberFormatter;
$formatter = new BulgarianNumberFormatter(style:\NumberFormatter::DECIMAL);
$formatter->format(5000); // 5000
$formatter->format(120500); // 120 500
$formatter->format(10005000); // 10 005 000
$formatter->format(3210005000); // 3 210 005 000
Обратите внимание: расширение INTL не запускается непосредственно PHP. Это оболочка библиотеки ICU, которая доступна практически в каждой системе и используется для форматирования и перевода — даже в веб-браузерах. Если вы считаете, что это следует изменить в библиотеке ICU, вы можете запросить изменения здесь: https://icu.unicode.org/bugs
Спасибо, я просил внести изменения. Посмотрим, реализовано ли это. Я скоро проверю ваш ответ, но, похоже, он сработает. Ценю!
Вот ошибка, которую я получил, когда попытался создать экземпляр этого класса: Fatal error: "static::" is not allowed in compile-time constants in C:\wamp64\www\AsphodelWorks.Projects\inc\numformat.class.php on line 16. Я без понятия что это значит.
Я заменил static на self, как рекомендовано здесь: stackoverflow.com/questions/28792904/…, и это сработало. Мне нужно было всего лишь изменить < 6 на < 5. Теперь я попытаюсь выяснить, как изменить GROUPING_SEPARATOR_SYMBOL на неразрывное пространство.
Я добавил функцию if ($numOfWholeDigits >= 5) { $this->setSymbol(self::GROUPING_SEPARATOR_SYMBOL, ' '); } to the format`, и она, похоже, работает! Ура!
Извиняюсь, я забыл static в этом контексте запрещено. Рад, что вы смогли разобраться и изменить его под свои нужды!
Не уверен, что это можно указать с помощью любого из параметров; возможно, вам придется создать свой собственный
DecimalFormatшаблон. Если вы проверите объяснение на unicode-org.github.io/icu-docs/apidoc/released/icu4c/…, оно покажет, что шаблон#,##,##0, примененный к значению123456789, приведет к12,34,56,789- поэтому ваш шаблон будет иметь тогда это будет что-то вроде### #####0.