MessageFormatter 也是遵照的 ICU 规范,底层是 C 中的 ICU 操作,以是和 C 干系代码的利用办法没有太大的差异。
格式化// 格式化$fmt = new MessageFormatter("zh_CN", "{0,number,integer} 只猴子在 {1,number,integer} 颗树上,每只树上有 {2,number} 只猴子");echo $fmt->format([4560, 123, 4560 / 123]), PHP_EOL;// 4,560 只猴子在 123 颗树上,每只树上有 37.073 只猴子$fmt = new MessageFormatter("de", "{0,number,integer} Affen auf {1,number,integer} Bäumen sind {2,number} Affen pro Baum");echo $fmt->format([4560, 123, 4560 / 123]), PHP_EOL;// 4.560 Affen auf 123 Bäumen sind 37,073 Affen pro Baumecho MessageFormatter::formatMessage("zh_CN", "{0,number,integer} 只猴子在 {1,number,integer} 颗树上,每只树上有 {2,number} 只猴子", [4560, 123, 4560 / 123]), PHP_EOL;// 4,560 只猴子在 123 颗树上,每只树上有 37.073 只猴子echo MessageFormatter::formatMessage("de", "{0,number,integer} Affen auf {1,number,integer} Bäumen sind {2,number} Affen pro Baum", [4560, 123, 4560 / 123]), PHP_EOL;// 4.560 Affen auf 123 Bäumen sind 37,073 Affen pro Baum
看到了吗?类似于 PDO 里预编译操作的占位符。在调用 format() 方法后,就可以让这个方法里面的参数来更换占位符的内容。我们可以指定占位的所利用的参数类型和位置,{参数下标,类型,扩展类型} 这便是这个信息数据格式化的占位符的规则定义。看起来貌似很大略呀,实在它还有更多的功能,我们将在后面看到。不过须要把稳的是,它只支持数字、日期、文本片段类型,文章末了的参考链接中有官方的文档可以查阅。
MessageFormatter::formatMessage() 这个静态方法可以一次性地指定措辞、预操作语句以及更换参数,不须要前辈行实例化再调用 format() 方法。
反格式化(根据规则获取参数数组)
能够进行格式化,当然我们也能够根据语句规则来反格式化干系的字符串从而得到对应占位符的参数列表。
// 根据格式化规则反向获取规则参数$fmt = new MessageFormatter('zh_CN', "{0,number,integer} 只猴子在 {1,number,integer} 颗树上,每只树上有 {2,number} 只猴子");$res = $fmt->parse("4,560 只猴子在 123 树上,每只树上有 37.073 只猴子");var_export($res); // falseecho "ERROR: " . $fmt->getErrorMessage() . " (" . $fmt->getErrorCode() . ")\n";// ERROR: Parsing failed: U_MESSAGE_PARSE_ERROR (6)$fmt = new MessageFormatter('en_US', "{0,number,integer} monkeys on {1,number,integer} trees make {2,number} monkeys per tree");$res = $fmt->parse("4,560 monkeys on 123 trees make 37.073 monkeys per tree");var_export($res);// array (// 0 => 4560,// 1 => 123,// 2 => 37.073,// )$fmt = new MessageFormatter('de', "{0,number,integer} Affen auf {1,number,integer} Bäumen sind {2,number} Affen pro Baum");$res = $fmt->parse("4.560 Affen auf 123 Bäumen sind 37,073 Affen pro Baum");var_export($res);// array (// 0 => 4560,// 1 => 123,// 2 => 37.073,// )$fmt = MessageFormatter::parseMessage('de', "{0,number,integer} Affen auf {1,number,integer} Bäumen sind {2,number} Affen pro Baum", "4.560 Affen auf 123 Bäumen sind 37,073 Affen pro Baum");var_export($fmt);// array (// 0 => 4560,// 1 => 123,// 2 => 37.073,// )
利用实例化后的 parse() 方法或者直策应用静态方法 MessageFormatter::parseMessage() 就能够实现这样的操作。须要把稳的是,对付 zh_CN ,也便是中文措辞区域设置来说,这个操作是会出问题的。通过 getErrorMessage() 和 getErrorCode() 就可以看到缺点信息以及缺点代码,可以看到对付中文来说,直接返回的缺点信息便是解析失落败。
设置获取规则在实例化的工具中,我们还可以动态地修正规则语句。
// 设置获取规则$fmt = new MessageFormatter("zh_CN", "{0, number} 猴子在 {1, number} 颗树上");echo "默认规则: '" . $fmt->getPattern(), PHP_EOL; // 默认规则: '{0, number} 猴子在 {1, number} 颗树上'echo "格式化结果:" . $fmt->format(array(123, 456)), PHP_EOL; // 格式化结果:123 猴子在 456 颗树上$fmt->setPattern("{0, number} 颗树上有 {1, number} 猴子");echo "新规则: '" . $fmt->getPattern(), PHP_EOL; // 新规则: '{0, number} 颗树上有 {1, number} 猴子'echo "新规则格式化结果: " . $fmt->format(array(123, 456)), PHP_EOL; // 新规则格式化结果: 123 颗树上有 456 猴子
非常大略的两个方法,setPattern() 用于设置当前实例化对应的格式化规则,getPattern() 用于获取查看当前实例化工具的格式化规则。在设置了新规则之后,进行 format() 或者 parse() 时便是按照新的规则语句来实行的了。
格式化完全示例上面说过,除了数字之外,还可以有日期格式的占位符,我们就来演示一下。
echo MessageFormatter::formatMessage('zh_CN', '本日是 {3, date, full},当前韶光为 {3, time, ::Hms}, 我要准备开始 {0} 了,本日要和 {2,number,integer} 人见面,还不能忘了要交 {1,number,currency} 元的电费', ['上班', 35.33, 25, new DateTime()]), PHP_EOL;// 本日是 2020年11月16日星期一,当前韶光为 10:09:30, 我要准备开始 上班 了,本日要和 25 人见面,还不能忘了要交 ¥35.33 元的电费
在这段语句中,我们给定的参数顺序并不是按照语句中占位符涌现的顺序,这样并没有影响,只须要指定对应位置的参数数组下标即可,比如第一个 {3, date, full} 指定的便是参数数组中的第4个元素(从0开始)。date 类型、time 类型都是可以指定的类型,当然我们也可以指定它们的 日期格式 比如第二个占位符我们就只显示当前的时分秒信息。
如果是字符串信息,那么只须要一个大略的 {0} 就可以了,字符串不须要太多的类型设置。而数字类型则可以直接格式化为货币等类型,就像我们之前讲过的 NumberFormatter 中可以指定的那些类型一样。
看完这一个示例是不是就觉得到这个 MessageFormatter 的强大之处了?别急,它还有更牛X的能力。
根据参数内容进行复数显示对付复数来说,实在中文语法中并没有这样的语句,比如说一只猫是 a cat ,两只猫是 two cats 。
echo MessageFormatter::formatMessage('en_US', 'I Have {0, plural, =0{no cat} =1{a cat} other{# cats}}', [0]),PHP_EOL; // I Have no catecho MessageFormatter::formatMessage('en_US', 'I Have {0, plural, =0{no cat} =1{a cat} other{# cats}}', [1]),PHP_EOL; // I Have a catecho MessageFormatter::formatMessage('en_US', 'I Have {0, plural, =0{no cat} =1{a cat} other{# cats}}', [2]),PHP_EOL; // I Have 2 cats
虽说参数类型的 plural 是复数的意思,不过实在我们可以将它看做是一个 switch() 语句的用法。
echo MessageFormatter::formatMessage('zh_CN', '我{0, plural, =0{没有猫} other{有 # 只猫}}', [0]),PHP_EOL; // 我没有猫echo MessageFormatter::formatMessage('zh_CN', '我{0, plural, =0{没有猫} other{有 # 只猫}}', [1]),PHP_EOL; // 我有 1 只猫echo MessageFormatter::formatMessage('zh_CN', '我{0, plural, =0{没有猫} other{有 # 只猫}}', [2]),PHP_EOL; // 我有 2 只猫
# 号便是对应的参数值的原内容,这一套语法又让这个 MessageFormatter 类上了一个层次吧,还有呢!
我们先来看看这个问题:
echo MessageFormatter::formatMessage('en_US', 'I Have {0, plural, =0{no cat} =1{a cat} other{# cats}}', [-1]),PHP_EOL; // I Have -1 cats
参数传错了,-1 只猫可不对吧,没紧要,还有别的处理办法办理这个问题。
选择条件规则// 选择表达式echo MessageFormatter::formatMessage('en_US', 'I Have {0, choice, 0 #no cats| 1 #one cat | 2 #{0, number} cats}', [-1]),PHP_EOL; // I Have no catsecho MessageFormatter::formatMessage('en_US', 'I Have {0, choice, 0 #no cats| 1 #one cat | 2 #{0, number} cats}', [0]),PHP_EOL; // I Have no catsecho MessageFormatter::formatMessage('en_US', 'I Have {0, choice, 0 #no cats| 1 #one cat | 2 #{0, number} cats}', [1]),PHP_EOL; // I Have one catecho MessageFormatter::formatMessage('en_US', 'I Have {0, choice, 0 #no cats| 1 #one cat | 2 #{0, number} cats}', [2]),PHP_EOL; // I Have 2 catsecho MessageFormatter::formatMessage('en_US', 'I Have {0, choice, 0 #no cats| 1 #one cat | 2 #{0, number} cats}', [10]),PHP_EOL; // I Have 10 cats
choice 这个单词就能看出来,这是一个选择干系的语法。后面的参数实在是一个区间,分别代表 <= 0 | 1 | >=2 的范围内利用哪个内容。其余,一个占位符规则里面还可以连续套占位符号的。
总结又大开了一回眼界。文章开头的两部分内容实在并没有什么惊喜的地方,毕竟普通的字符串更换都能办到,不过越今后面可是越来越精彩啊。当然,它的干系规则语法该当还有更多,只是这些资料非常少,不管是 PHP 官方文档还是 ICU 的官方文档都没有找到过多的先容。以是我们还是报以学习理解的态度先知道有这么回事,将来创造更有趣的资料后再来分享学习吧,也希望有利用过的朋友留言一起谈论哦!
测试代码:
https://github.com/zhangyue0503/dev-blog/blob/master/php/202011/source/5.PHP中针对区域措辞标记信息的操作.php
参考文档:
https://www.php.net/manual/zh/class.messageformatter.php
http://userguide.icu-project.org/formatparse/messages