关于php:学习PHP中的信息格式化操作

45次阅读

共计 5759 个字符,预计需要花费 15 分钟才能阅读完成。

在国际化组件的学习过程中,咱们曾经接触过了 NumberFormatter 这种数字的格式化操作,它能够让咱们将数字转换成规范格局、货币、本地语言等模式。明天咱们来学习的是另一种专门用于信息格式化的类 MessageFormatter,它次要是针对字符串的操作。

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 Baum

echo 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); // false
echo "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 cat
echo MessageFormatter::formatMessage('en_US', 'I Have {0, plural, =0{no cat} =1{a cat} other{# cats}}', [1]),PHP_EOL; // I Have a cat
echo 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 cats
echo MessageFormatter::formatMessage('en_US', 'I Have {0, choice, 0 #no cats| 1 #one cat | 2 #{0, number} cats}', [0]),PHP_EOL; // I Have no cats
echo MessageFormatter::formatMessage('en_US', 'I Have {0, choice, 0 #no cats| 1 #one cat | 2 #{0, number} cats}', [1]),PHP_EOL; // I Have one cat
echo MessageFormatter::formatMessage('en_US', 'I Have {0, choice, 0 #no cats| 1 #one cat | 2 #{0, number} cats}', [2]),PHP_EOL; // I Have 2 cats
echo 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

===========

各自媒体平台均可搜寻【硬核项目经理】

正文完
 0