不晓得大众有无认识过,针对数字格式来讲,西方国家会以三位为一个进位,运用逗号来分隔。例如,12345678,用标准的格式来暗示的话便是 12,345,678 。不外咱们中文其实并不会有这般的分隔符,另一像某些地区则是以空格为分隔的,这个咱们马上经过代码就能够看到。其实在之前的文案中咱们就已然接触过一点这方面的知识,学习PHP中的国际化功能来查看货币及日期信息,今天就来仔细的学习一遍。至于为何要格式化数字、货币这些内容呢?咱们将在文案讲解中逐一说明。
数字标准格式
首要还是看咱们开头介绍的标准数字格式。 $localeArr = [en_US, zh_CN, ja_JP, de_DE, fr_FR, ar-IQ, ru_RU];
foreach ($localeArr as $locale) {
$fmt = new NumberFormatter($locale, NumberFormatter:ECIMAL);
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:1 234 567,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:$1,234,567.89
// en_US:RUR 1,234,567.89
// zh_CN:¥1,234,567.89
// zh_CN:RUR 1,234,567.89
// ja_JP:¥1,234,568
// ja_JP:RUR 1,234,567.89
// de_DE:1.234.567,89 €
// de_DE:1.234.567,89 RUR
// fr_FR:1 234 567,89 €
// fr_FR:1 234 567,89 RUR
// ar-IQ:١٬٢٣٤٬٥٦٨ د.ع.
// ar-IQ:١٬٢٣٤٬٥٦٧٫٨٩ RUR
// ru_RU:1 234 567,89 ₽
// ru_RU:1 234 567,89 р.
在这段代码中,咱们运用了两种模式的输出。第1个指的是定 NumberFormatter 的第二个参数为 CURRENCY ,亦便是指定格式化为货币格式。其实便是为标准格式的数字前后增多了对应地区的代币符号。例如咱们中国和日本通用的 ¥ ,通常是放在金额的前面,而欧洲的则运用 € 欧元标识放在金额的后面。
另一种形式便是 formatCurrency() 这个办法能够指定一个货币类型,倘若不是这个类型的区域设置的话,就直接输出这个货币字符。在测试代码中,咱们给定的是俄罗斯的老卢布,其它区域中会直接输出 RUR ,而在区域设置为俄罗斯时,输出的便是标准的老卢布符号(此刻运用的是新卢布,符号是 ₽ ,老卢布便是 р.)。
仔细的地区格式化样式
是不是感觉已然很高挑上了?不不不,上面两种格式只是开胃菜,真正好玩的此刻马上端给你。 $fmt = new NumberFormatter(zh_CN, NumberFormatter:ERCENT);
echo $fmt->format(1234567.891234567890000), PHP_EOL; // 123 456 789 %
$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:URATION);
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.# 公斤");
var_dump($fmt->getPattern()); // string(6) "0.# 公斤"
echo $fmt->format(1234567.891234567890000), PHP_EOL; // 1234567.9 公斤
看出来了吗?咱们运用 setPattern() 办法来定义了一个带 公斤 的格式规则,很表示,咱们是需要一个暗示重量的格式。而后仅保存一位小数点,不需要分隔符号。这般再次运用 format() 办法的时候就会根据咱们指定的格式来进行格式化了。
属性操作
当然,除了直接设置规则格式外,咱们还能够指定有些属性值来改变当前的格式效果。 $fmt = new NumberFormatter( zh_CN, NumberFormatter:ECIMAL );echo "Digits: ".$fmt->getAttribute(NumberFormatter::MAX_FRACTION_DIGITS), PHP_EOL; // Digits: 3
echo $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: 2
echo $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; // 1*234*567.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:ECIMAL );
$num = "1,234,567.891";
echo $fmt->parse($num)."\n"; // 1234567.891
echo$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.89
var_dump($currency); // string(3) "CNY"
两个办法,第1个是 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
|