1. 程式人生 > 程式設計 >PHP中資訊格式化操作詳解(MessageFormatter類)

PHP中資訊格式化操作詳解(MessageFormatter類)

目錄
  • 前言
  • 格式化
  • 反格式化(根據規則獲取引數陣列)
  • 設定獲取規則
  • 格式化完整示例
    • 根據引數內容進行復數顯示
    • 選擇條件規則
  • 總結

    前言

    在國際化元件的學習過程中,我們已經接觸過了 NumberFormatter 這種數字的格式化操作,它可以讓我們將數字轉換成標準格式、貨幣、本地語言等形式。今天我們來學習的是另一種專門用於資訊格式化的類 MessageFormatter ,它主要是針對字串的操作。

    MessageFormatter 也是遵循的 ICU 規範,底層是 C 中的 ICU 操作,所以和 C 相關程式碼的使用方式沒有太大的區別。

    格式化

    // 格式化
    $fmt = new MessageFormatter("zh_CN","{0,number,integer} 只猴子在 {1,integer} 顆樹上,每隻樹上有 {2,number} 只猴子");
    echo $fmt->format([
    4560,123,4560 / 123]),_EOL; // 4,560 只猴子在 123 顆樹上,每隻樹上有 37.073 只猴子 $fmt = new MessageFormatter("de",integer} Affen auf {1,integer} Bäumen sind {2,number} Affen pro Baum"); echo $fmt->format([4560,PHP_EOL; // 4.560 Affen auf 123 Bäumen sind 37,073 Affen pro Baum echo MessageFormatter::formatMessage("zh_CN",number} 只猴子",[4560,
    4560 / 123]),PHP_EOL; // 4,560 只猴子在 123 顆樹上,每隻樹上有 37.073 只猴子 echo MessageFormatter::formatMessage("de",number} Affen pro Baum",073 Affen pro Baum

    看到了嗎?類似於 PDO 裡預編譯操作的佔位符。在呼叫 format() 方法後,就可以讓這個方法裡面的引數來替換佔位符的內容。我們可以指定佔位的所使用的引數型別和位置,{引數下標,型別,擴充套件型別} 這就是這個資訊資料格式化的佔位符的規則定義。看起來貌似很簡單呀,其實它還有更多的功能,我們將在後面看到。不過需要注意的是,它只支援數字、日期、文字片段型別,文章最後的參考連結中有官方的文件可以查閱。

    MessageFormatter::formatMessage() 這個靜態方法可以一次性地指定語言、預操作語句以及替換引數,不需要先進行例項化再呼叫 format() 方法。

    反格式化(根據規則獲取引數陣列)

    能夠進行格式化,當然我們也能夠根據語句規則來反格式化相關的字串從而獲得對應占位符的引數列表。

    // 根據格式化規則反向獲取規則引數
    $fmt = new MessageFormatter('zh_CN',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',integer} monkeys on {1,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',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,//   )
    
    $fmt = MessageFormatter::parseMessage('de',"4.560 Affen auf 123 Bäumen sind 37,073 Affen pro Baum");
    var_export($fmt);
    // array (
    //     0 => 4560,//   )
    

    使用例項化後的 parse() 方法或者直接使用靜態方法 MessageFormatter::parseMessage() 就能夠實現這樣的操作。需要注意的是,對於 zh_CN ,也就是中文語言區域設定來說,這個操作是會出問題的。通過 getErrorMessage() 和 getErrorCode() 就可以看到錯誤資訊以及錯誤程式碼,可以看到對於中文來說,直接返回的錯誤資訊就是解析失敗。

    設定獲取規則

    在例項化的物件中,我們還可以動態地修改規則語句。

    // 設定獲取規則
    $fmt = new MessageFormatter("zh_CN",number} 猴子在 {1,number} 顆樹上");
    echo "預設規則: '" . $fmt->getPattern(),PHP_EOL; // 預設規則: '{0,number} 顆樹上'
    echo "格式化結果:" . $fmt->format(array(123,456)),PHP_EOL; // 格式化結果:123 猴子在 456 顆樹上
    
    $fmt->setPattern("{0,number} 顆樹上有 {1,number} 猴子");
    echo "新規則: '" . $fmt->getPattern(),PHP_EOL; //http://www.cppcns.com 新規則: '{0,number} 猴子'
    echo "新規則格式化結果: " . $fmt->format(array(123,PHP_EOL; // 新規則格式化結果:123 顆樹上有 456 猴子
    

    非常簡單的兩個方法,setPattern() 用於設定當前例項化對應的格式化規則,getPattern() 用於獲取檢視當前例項化物件的格式化規則。在設定了新規則之後,進行 format() 或者 parse() 時就是按照新的規則語句來執行的了。

    格式化完整示例

    上面說過,除了數字之外,還可以有日期格式的佔位符,我們就來演示一下。

    echo MessageFormatter::formatMessage('zh_CN','今天是 {3,date,full},當前時間為 {3,time,::Hms},我要準備開始 {0} 了,今天要和 {2,integer} 人見面,還不能忘了要交 {1,currency} 元的電費',['上班',35.33,25,new DateTime()]),PHP_EOL;
    // 今天是 2020年11月16日星期一,當前時間為 10:09:30,我要準備開始 上班 了,今天要和 25 人見面,還不能忘了要交 ¥35.33 元的電費
    

    在這段語句中,我們給定的引數順序並不是按照語句中佔位符出現的順序,這樣並沒有影響,只需要指定對應位置的引數陣列下標即可,比如第一個 {3,full} 指定的就是引數陣列中的第4個元素(從0開始)。date 型別、time 型別都是可以指定的型別,當然我們也可以指定它們的 日期格式 比如第二個佔位符我們就只顯示當前的時分秒資訊。

    如果是字串資訊,那麼只需要一個簡單的 {0} 就可以了,字串不需要太多的型別設定。而數字型別則可以直接格式化為貨幣等型別,就像我們之前講過的 NumberFormatter 中可以指定的那些型別www.cppcns.com一樣。

    看完這一個示例是不是就感覺到這個 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',[1]),PHP_EOL; // I Have a cat
    echo MessageFormatter::formatMessage('en_US',[2]),PHP_EOL; // I Have 2 cats
    

    雖說引數型別的 plural 是複數的意思,不過其實我們可以將它看做是一個 switch() 語句的用法。

    echo MessageFormatter::formatMessage('zh_CN','我{0,=0{沒有貓} other{有 # 只貓}}',PHP_EOL; // 我沒有貓
    echo MessageFormatter::formatMessage('zh_CN',PHP_EOL; // 我有 1 只貓
    echo MessageFormatter::formatMessage('zh_CN',PHP_EOL; // 我有 2 只貓
    

    # 號就是對應的引數值的原內容,這一套語法又讓這個 MessageFormatter 類上了一個層次吧,還有呢!我們先來看看這個問題:

    echo MessageFormatter::formatMessage('en_US',[-1]),PHP_EOL; // I Have -1 cats
    

    引數傳錯了,-1 只貓可不對吧,沒關係,還有別的處理方式解決這個問題。

    選擇條件規則

    // 選擇表示式
    echo MessageFormatter::formatMessage('en_US',choice,0 #no cats| 1 #one cat | 2 #{0,number} cats}',PHP_EOL; // I Have no cats
    echo MessageFormatter::formatMessage('en_US',PHP_EOL; // I Have one cat
    echo MessageFormatter::formatMessage('en_US',PHP_EOL; // I Have 2 cats
    echo MessageFormatter::formatMessage('en_US',[10]),PHP_EOL; // I Have 10 cats
    

    choice 這個單詞就能看出來,這是一個選擇相關的語法。後面的引數其實是一個區間,分別代表 <= 0 | 1 | >=2 的範圍內使用哪個內容。另外,一個佔位符規則裡面還可以繼續套佔位符號的。

    總結

    又大開了一回眼界。文章開頭的兩部分內容其實並沒有什麼驚喜的地方,畢竟普通的字串替換都能辦到,不過越往後面可是越來越精彩啊。當然,它的相關規則語法應該還有更多,只是這些資料非常少,不管是 PHP 官方文件還是 ICU 的官方文件都沒有找到過多的介紹。所以我們還是報以學習瞭解的態度先知道有這麼回事,將來發現更有趣的資料後再來分享學習吧,也希望有使用過的朋友留言一起討論哦!

    到此這篇關於PHP中資訊格式化操作的文章就介紹到這了,更多相關PHP中資訊格式化內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!

    測試程式碼:

    .com/zhangyue050…

    參考文件:

    www.php.net/manual/zh/c…

    userguide.icu-project.org/formatparse…