$localeArr = ['en_US', 'zh_CN', 'ja_JP', 'de_DE', 'fr_FR', 'ar-IQ', 'ru_RU'];foreach ($localeArr as $locale) { $fmt = new NumberFormatter($locale, NumberFormatter::DECIMAL); echo $locale . ':', $fmt->format(1234567.891234567890000), PHP_EOL;}// en_US:1,234,567.891// zh_CN:1,234,567.891// ja_JP:1,234,567.891// de_DE:1.234.567,891// fr_FR:1 234 567,891// ar-IQ:١٬٢٣٤٬٥٦٧٫٨٩١// ru_RU:1234567,891
我们先指定了许多的国家地区编码,然后循环它们,利用 NumberFormatter 工具来对他们进行实例化。第二个参数便是要实例化的格式类型,这里我们指定的是数字类型。然后利用 format() 方法就可以对指定的数字进行格式化地输出了。可以看到,德国是利用 . 来分隔进位,利用逗号来做为小数点。而法国和俄罗斯则是利用空格来表示进位,逗号表示小数点。其它国家则是沿用标准的英式表示。
对付很多财务及银行项目来说,标准数字格式非常有用。每每我们打仗到比较多的是在汇款时要填写的普通数字、中文大写,而一些面向企业和涉外的公司财务也须要这种标准格式的数字来进行存根的记录。既然说到财务了,我们再看看货币格式的展示。
货币格式foreach ($localeArr as $locale) { $fmt = new NumberFormatter($locale, NumberFormatter::CURRENCY); echo $locale . ':', $fmt->format(1234567.891234567890000), PHP_EOL; echo $locale . ':', $fmt->formatCurrency(1234567.891234567890000, 'RUR'), PHP_EOL;}// en_US:,234,567.89// en_US:RUR1,234,567.89// zh_CN:¥1,234,567.89// zh_CN:RUR1,234,567.89// ja_JP:¥1,234,568// ja_JP:RUR1,234,567.89// de_DE:1.234.567,89€// de_DE:1.234.567,89RUR// fr_FR:1 234 567,89€// fr_FR:1 234 567,89RUR// ar-IQ:١٬٢٣٤٬٥٦٨د.ع.// ar-IQ:١٬٢٣٤٬٥٦٧٫٨٩RUR// ru_RU:1234567,89₽// ru_RU:1234567,89р.
在这段代码中,我们利用了两种模式的输出。第一个是指定 NumberFormatter 的第二个参数为 CURRENCY ,也便是指定格式化为货币格式。实在便是为标准格式的数字前后增加了对应地区的代币符号。比如我们中国和日本通用的 ¥ ,一样平常是放在金额的前面,而欧洲的则利用 € 欧元标识放在金额的后面。
另一种形式便是 formatCurrency() 这个方法可以指定一个货币类型,如果不是这个类型的区域设置的话,就直接输出这个货币字符。在测试代码中,我们给定的是俄罗斯的老卢布,其它区域中会直接输出 RUR ,而在区域设置为俄罗斯时,输出的便是标准的老卢布符号(现在利用的是新卢布,符号是 ₽ ,老卢布便是 р.)。
详细的地区格式化样式是不是觉得已经很高大上了?不不不,上面两种格式只是开胃菜,真恰好玩的现在立时端给你。
$fmt = new NumberFormatter('zh_CN', NumberFormatter::PERCENT);echo $fmt->format(1234567.891234567890000), PHP_EOL; // 123456789%$fmt = new NumberFormatter('zh_CN', NumberFormatter::SCIENTIFIC);echo $fmt->format(1234567.891234567890000), PHP_EOL; // 1,2345678912345679E6$fmt = new NumberFormatter('zh_CN', NumberFormatter::SPELLOUT);echo $fmt->format(1234567.891234567890000), PHP_EOL; // 一百二十三万四千五百六十七点八九一二三四五六七九$fmt = new NumberFormatter('zh_CN', NumberFormatter::SPELLOUT);echo $fmt->format(1234502.891234567890000), PHP_EOL; // 一百二十三万四千五百〇二点八九一二三四五六七九$fmt = new NumberFormatter('zh_CN', NumberFormatter::ORDINAL);echo $fmt->format(1234567.891234567890000), PHP_EOL; // 第1,234,568$fmt = new NumberFormatter('zh_CN', NumberFormatter::DURATION);echo $fmt->format(1234567.891234567890000), PHP_EOL; // 1,234,568
PERCENT 不多说了,百分比,便是增加了一个百分号,而且不因此标准格式输出的,会以空格进行进位分隔。SCIENTIFIC 便是我们常见的科学计数法,测试代码中的结果便是 1.xx 的 10 的 6 次方的意思。
SPELLOUT 就比较厉害了,按当前区域措辞的拼写规则。没错,直接转换成了我们的中文表示。如果须要再转换成中文的大写,直接字符更换就可以了,这个绝对是这次文章的重大创造。之前在一家公司口试的时候就有人问过如何将数字转换成中文表示,由于很多的财务系统都须要这样的功能。不管是做帐还是处理发票,中文大写或小写都是系统自动输出的。当时还写了半天算法,如果大家自己写算法的时候除了须要把稳单位外,零的表示也是非常主要的一点,有兴趣的朋友可以自己考试测验一下。不过下回如果口试的时候有人问这个问题,那我直接就会甩出 NumberFormatter::SPELLOUT 这个神器了。
ORDINAL 是排序的表示,在中文中实在便是在前面增加了一个 第 字。DURATION 是基于持续韶光规则的格式。这两种都会抛弃掉小数点。
格式化规则设置虽说已经有这么多的规则格式供我们利用了,但大家的业务总是千奇百怪的,我们能不能定义自己的格式规则呢?既然这么写了,那当然是可以的啦。
var_dump($fmt->getPattern()); // string(8) "#,##0.##"$fmt->setPattern("#0.# kg");var_dump($fmt->getPattern()); // string(6) "0.# kg"echo $fmt->format(1234567.891234567890000), PHP_EOL; // 1234567.9 kg
看出来了吗?我们利用 setPattern() 方法来定义了一个带 kg 的格式规则,很显示,我们是须要一个表示重量的格式。然后仅保留一位小数点,不须要分隔符号。这样再次利用 format() 方法的时候就会按照我们指定的格式来进行格式化了。
属性操作当然,除了直接设置规则格式外,我们还可以指定一些属性值来改变当前的格式效果。
$fmt = new NumberFormatter( 'zh_CN', NumberFormatter::DECIMAL );echo "Digits: ".$fmt->getAttribute(NumberFormatter::MAX_FRACTION_DIGITS), PHP_EOL; // Digits: 3echo $fmt->format(1234567.891234567890000), PHP_EOL; // 1,234,567.891$fmt->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, 2);echo "Digits: ".$fmt->getAttribute(NumberFormatter::MAX_FRACTION_DIGITS), PHP_EOL; // Digits: 2echo $fmt->format(1234567.891234567890000), PHP_EOL; // 1,234,567.89
这段代码中,我们通过 setAttribute() 来设置 MAX_FRACTION_DIGITS 的值,用于改变最大保留的小数点位数。当然,不仅限于这一个属性,还有很多别的可以修正的属性,大家可以自行查阅官方手册。
分隔符号设置同样,我们可以直接修正格式化中的分隔符、小数点等利用的符号。直策应用 setSymbol() 方法就可以。
var_dump($fmt->getSymbol(NumberFormatter::GROUPING_SEPARATOR_SYMBOL)); // string(1) ","$fmt->setSymbol(NumberFormatter::GROUPING_SEPARATOR_SYMBOL, "");var_dump($fmt->getSymbol(NumberFormatter::GROUPING_SEPARATOR_SYMBOL)); // string(1) ""echo $fmt->format(1234567.891234567890000), PHP_EOL; // 1234567.891
与地区格式化关联的文本属性设置
我们还可以直接设置与地区格式化干系的一些文本信息,比如下面代码中利用 setTextAttribute() 修正了负号的表示。我们还可以利用这个方法修正间隔字符,货币编码等内容,大家可以自己对照官方文档测试学习。
var_dump($fmt->getTextAttribute(NumberFormatter::NEGATIVE_PREFIX)); // string(1) "-"echo $fmt->format(-1234567.891234567890000), PHP_EOL;$fmt->setTextAttribute(NumberFormatter::NEGATIVE_PREFIX, "负号 ");var_dump($fmt->getTextAttribute(NumberFormatter::NEGATIVE_PREFIX)); // string(7) "负号 "echo $fmt->format(-1234567.891234567890000), PHP_EOL; // 负号 1,234,567.891
获取地区信息
这两个方法便是大略地获取当前的地区信息了,之前在其它的文章中我们也讲过,VALID_LOCALE 是表示有效区域,ACTUAL_LOCALE 表示的是实际区域。
var_dump($fmt->getLocale(Locale::VALID_LOCALE)); // string(10) "zh_Hans_CN"var_dump($fmt->getLocale(Locale::ACTUAL_LOCALE)); // string(10) "zh_Hans_CN"
字符转换为数字、货币格式
我们能够将数字进行格式化地输出,输出之后的内容由于增加了分隔符之类的内容,以是都会转成字符串,那么,我们能不能把已经格式化过的标准数字字符再转回数字类型呢?
$fmt = new NumberFormatter( 'zh_CN', NumberFormatter::DECIMAL );$num = "1,234,567.891";echo $fmt->parse($num)."\n"; // 1234567.891echo $fmt->parse($num, NumberFormatter::TYPE_INT32)."\n"; // 1234567$fmt = new NumberFormatter( 'zh_CN', NumberFormatter::CURRENCY );echo $fmt->parseCurrency('¥1,234,567.89', $currency), PHP_EOL; // 1234567.89var_dump($currency); // string(3) "CNY"
两个方法,第一个是 parse() 方法,将标准格式的数字字符串转回指定类型的数字,可以指定为 TYPE_INT32 、TYPE_INT64 、TYPE_DOUBLE 、TYPE_CURRENCY 等类型。其余一个方法是 parseCurrency() 方法,从名字就可以看出,它是将货币格式转回数字,并且,很主要的一点是,它的第二个引用参数,可以将货币符号的通用编码也返回回来,比如测试代码中返回的 CNY 代表的便是我们利用的公民币。
缺点信息末了我们来看看 NumberFormatter 中的缺点信息如何获取。
echo $fmt->parseCurrency('1,234,567.89', $currency), PHP_EOL;var_dump($fmt->getErrorCode()); // int(9)var_dump(intl_is_failure($fmt->getErrorCode())); // bool(true)var_dump($fmt->getErrorMessage()); // string(36) "Number parsing failed: U_PARSE_ERROR"
在这里我们利用非标准的货币字符串来利用 parseCurrency() 进行转换,parseCurrency() 必须吸收的是带货币符号的内容,以是这里就产生了缺点。我们利用 getErrorCode() 可以获取到缺点码,利用 getErrorMessage() 可以获取到缺点信息。其余是一个 intl_is_failure() 函数,用于根据缺点码判断是否产生了区域措辞问题的缺点。
总结又是大开眼界的一次学习旅程,中文小写格式的转换真的是之前完备不知道的,而货币的相互转换我以为也完备可以运用到一些采集程序中,比如电商页面价格的采集剖析。总之,还是觉得到收成满满的。其余,这一套 NumberFormatter 工具也是供应了面向过程的函数式利用方法的,比如 numfmt_create() ,记住是 numfmt_ 开头的函数哦,不要和 number_format() 干系的函数搞混了。
测试代码:
https://github.com/zhangyue0503/dev-blog/blob/master/php/202011/source/4.学习PHP中国际化地数字格式处理.php
参考文档:
https://www.php.net/manual/zh/class.numberformatter.php