在國際化組件的學習過程中,我們已經接觸過了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 這個單字就能看出來,這是一個選擇相關的語法。後面的參數其實是一個區間,分別代表 9ce2a9552cf4ab57e0e396c4a2c78b14=2 的範圍內使用哪一個內容。另外,一個佔位符規則裡面還可以繼續套佔位符號的。
又大開了一回眼界。文章開頭的兩部分內容其實並沒有什麼驚喜的地方,畢竟普通的字串替換都能辦到,不過越往後面可是越來越精彩啊。
當然,它的相關規則語法應該還有更多,只是這些資料非常少,不管是 PHP 官方文件還是 ICU 的官方文件都沒有找到過多的介紹。
所以我們還是報以學習了解的態度先知道有這麼回事,將來發現更有趣的資料後再來分享學習吧,也希望有使用過的朋友留言一起討論哦!
推薦學習:php影片教學
以上是如何學習PHP中的資訊格式化操作的詳細內容。更多資訊請關注PHP中文網其他相關文章!