Как я могу изменить 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,

Другие вопросы по тегам