Как я могу изменить NumberFormatter::parseCurrency() поведение принятия пробела и неразрывного пробела?
Я пытаюсь разобрать строки локализованной валюты в валюте и с плавающей запятой.
Некоторое время все работает хорошо, сейчас у нас проблемы. Похоже, что NumberFormatter:: parseCurrency использует дополнительный невидимый символ:
Testcode:
<?php
$formatter = new NumberFormatter("de_DE", NumberFormatter::CURRENCY);
var_dump(array(
$formatter->parseCurrency("88,22 €", $curr), // taken from output of $formatter->format(88.22)
$formatter->parseCurrency("88,22 €", $curr), // input with keyboard
$formatter->parseCurrency("88,22 \xE2\x82\xAc", $curr), // just a test
$formatter->format(88.22),
"88,22 €" // keyboard input
));
Выход:
array(5) {
[0]=> float(88,22)
[1]=> bool(false)
[2]=> bool(false)
[3]=> string(10) "88,22 €" // this as input works
[4]=> string(9) "88,22 €" // this not...
}
Как вы можете видеть, есть разница в длине строки выходных данных 3 и 4.
Я получаю те же результаты в PHP 5.3 (Ubuntu с включенной mbstring) и 5.4 (Zend Server в Mac OS X).
Основная проблема в том, что входные значения из моей формы (приложение ZF1) одинаково выводятся с индексом 4...
какие-либо предложения? заранее спасибо
Edit1:
hexdump рабочего значения:
00000000 38 38 2c 32 32 c2 a0 e2 82 ac 0a |88,22......|
0000000b
шестнадцатеричная неработающая ценность:
00000000 38 38 2c 32 32 20 e2 82 ac 0a |88,22 ....|
0000000a
Edit2:
Похоже, проблема с использованным whitepsace. c2 a0 - это пространство без разрывов и (возможно?) требуется NumberFormatter:: parseCurrency (). но 0x20 - это пространство по умолчанию (которое вводится в форме ввода). Текущий обходной путь - замена пустого пространства на NO-BREAK SPACE на $value = str_replace("\x20", "\xC2\xA0", $value);
Edit3:
В другой системе (Mac OS X с Zend Server 5.6, mbstring включен, PHP 5.3.14) все работает как положено:
array(5) {
[0]=> float(88,22)
[1]=> float(88,22)
[2]=> float(88,22)
[3]=> string(9) "88,22 €"
[4]=> string(9) "88,22 €"
}
Edit4:
Основное различие между работой с пространством и работой с конфигурацией без прерывания пространства заключается в версии ICU:
рабочая версия:
intl
Internationalization support => enabled
version => 1.1.0
ICU version => 3.8.1
Directive => Local Value => Master Value
intl.default_locale => no value => no value
intl.error_level => 0 => 0
не рабочая версия:
intl
Internationalization support => enabled
version => 1.1.0
ICU version => 4.8.1.1
ICU Data version => 4.8.1
Directive => Local Value => Master Value
intl.default_locale => no value => no value
intl.error_level => 0 => 0
1 ответ
NumberFormatter::parseCurrency
является тонкой оболочкой для функции библиотеки ICU unum_parseDoubleCurrency
( см. источник).
Функция библиотеки ICU ограничительна тем, что она будет анализировать только те строки, которые могут возникнуть в результате ее двойной функции unum_formatDoubleCurrency
, Формат определяется данными локали Unicode, которые задают неразрывный пробел между значением валюты и числовым значением. Очевидно, более ранняя версия библиотеки принимала другие пробельные символы.
Короче говоря, вы не можете сделать NumberFormatter::parseCurrency
принять пробелы. Тем не мение, Zend_Currency
должен также выводить неразрывные пробелы по умолчанию:
$currency = new Zend_Currency(array(
'currency' => 'EUR',
'value' => 88.22,
), 'de_DE');
var_dump(
strval($currency), // 88,22 €
strpos($currency, "\x20"), // false
strpos($currency, "\xc2\xa0") // 5
);
Вопрос в том, какая часть вашего приложения выводит пробел и как вы к нему обращаетесь. Вы упоминаете, что это часть вашей формы, так что, возможно, вы могли бы взглянуть на то, чтобы форма возвращала валюту и значение как отдельные поля, чтобы вам не приходилось беспокоиться о разборе числа. Если пользователь сам вводит строку "88,22 €", вы можете столкнуться с большим количеством проблем, чем просто проблема с пробелами. Сказав это, обходной путь, который вы упомянули (замена \x20
с \xc2\xa0
) это единственный способ решить эту проблему, если вы хотите использовать NumberFormatter
,