【问题标题】:How can I change NumberFormatter::parseCurrency() behavior of accepting white space and non breaking space?如何更改 NumberFormatter::parseCurrency() 接受空白和非中断空间的行为?
【发布时间】:2013-05-02 12:56:16
【问题描述】:

我正在尝试将本地化的货币字符串解析为货币和浮点值。

在一段时间内一切正常,现在我们遇到了一些问题。似乎 NumberFormatter::parseCurrency 使用了一个额外的不可见字符:

测试代码:

<?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(启用了 mbstring 的 ubuntu)和 5.4(Mac OS X 上的 Zend Server)中得到了相同的结果。

主要问题是,我的表单(ZF1 应用程序)的输入值与索引为 4 的输出相同...

有什么建议吗?提前致谢

编辑1:

工作值的hexdump:

00000000  38 38 2c 32 32 c2 a0 e2  82 ac 0a                 |88,22......|
0000000b

非工作值的hexdump:

00000000  38 38 2c 32 32 20 e2 82  ac 0a                    |88,22 ....|
0000000a

编辑2:

使用的whitepsace似乎有问题。 c2 a0 是 NO-BREAK SPACE 并且(也许?) NumberFormatter::parseCurrency() 需要。但 0x20 是默认空间(在输入表单中输入)。 当前的解决方法是用$value = str_replace("\x20", "\xC2\xA0", $value); 替换空格与NO-BREAK SPACE

编辑3:

在另一个系统上(带有 Zend Server 5.6 的 Mac OS X,启用 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 €"
}

编辑4:

使用空间和使用不间断空间配置的主要区别在于 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

【问题讨论】:

  • 只是一个想法:来自格式化程序 UTF-8 编码 (0x20AC) 的 € 符号和来自键盘 Latin-1 (0x80) 的符号?据我所知 strlen() 函数不知道 Unicode 字符。如果它被 var_dump() 内部使用,那将解释附加字符。
  • 我的终端应用程序 (iTerm2) 使用 Unicode(UTF-8) 作为终端仿真。此外,此错误/行为是通过 html 表单文本输入字段从浏览器输入数据发生的。我添加了 hexdump 输出以进行澄清。
  • 文件是否保存为UTF-8?
  • 是的,在所有经过测试的系统上

标签: php icu intl numberformatter


【解决方案1】:

NumberFormatter::parseCurrency 是 ICU 库函数 unum_parseDoubleCurrency (see source) 的薄包装。

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 €”,您可能会遇到更多问题,而不仅仅是空格问题。话虽如此,如果您想使用NumberFormatter,您提到的解决方法(将\x20 替换为\xc2\xa0)是解决该问题的唯一方法。

【讨论】:

  • 感谢您的解释! Zend_Currency 返回正确的值。但是我的表单允许使用带有货币符号的本地格式的浮点数直接用户输入。 Zend 框架的完整解决方案是添加到元素的自定义过滤器,因为这在 NumberFormatter 或 pecl-intl 上不是真正的问题。
猜你喜欢
  • 2021-03-07
  • 1970-01-01
  • 2020-10-11
  • 1970-01-01
  • 1970-01-01
  • 2023-03-16
  • 1970-01-01
  • 2011-03-31
  • 2016-12-04
相关资源
最近更新 更多