最近在做一個專案的時候遇到這樣一個需求:客戶讓我把手機號碼顯示為 138-8888-8888的格式。
心想這還不簡單,不加思索的敲下了這段程式碼:
function format_mobile($mobile){ return implode('-', sscanf($mobile, '%3s%4s%4s')); }
執行之後得到結果正是我想要的。可是,我總覺得這就完了?難道沒有更簡單的方法了?
思考片刻又寫了這樣一個函式:
function format_mobile2($mobile){ return preg_replace('/^(\d{3})(\d{4})(\d{4})$/', '$1-$2-$3', $mobile); }
執行,挺好,也能得到正確的結果。不過這個好像也沒有比上面更簡單,少呼叫一個函式而已,但是程式碼還變多了。。。
接著,需求又來了,所有的檔案大小用位元組為單位,但是從又往左每三位用逗號分割。
看到這個需求的第一反應是,剛格式化手機號碼的第二種方案不正好麼,4位改三位,分隔符換掉就OK。
開始編寫程式碼,當寫到正規表示式的時候發現,完了,手機號位數確定的,檔案位元組大小位數不定的。繼續思考,調整了正規表示式如下:
function format_filesize($filesize){ return preg_replace('/(\d)(?=(\d{3})+$)/', '$1,', $filesize); }
執行,結果正確。
這裡,我解釋一下這段正規表示式:
(\d) //第一個括號主要是用來匹配一個數字 //我們要往這個數字的後面新增一個逗號 (?=) //第二個括號是一個正向肯定查詢 //也就是說,前面匹配的那個數字後面的字串必須符合這個括號裡面的規則 (\d{3})+$ //這是第二個括號裡面的規則 //這裡又有一個括號,這個括號僅代表 \d{3} 為一個整體 //\d{3} 匹配3個數字 //後面的 + 號代表前面括號的內容可以出現 N 次,N >= 1 //(\d{3})+ 即為匹配3的倍數個數字 //最後的 $ 匹配字串的結尾,即3的倍數個數字之後不能再有任何字元 //根據上面的解釋,我們可以看出: //這段正規表示式主要是用來找一個數字,這個數字的特徵是 //後面的字元必須是3的倍數個數字,只到結尾 //例如:1234567890這10個數字 //後面為3的倍數個數字的數字分別為1,4,7 //那我們只需要找到它們,分別在它們的後面新增逗號就OK了
然後,又想到,在做電商專案的時候,經常遇到金額的格式化,也是沒三位新增一個逗號。少有不同的是,金額不是從字串結尾開始算的,而是從小數點開始往左邊數的。
仔細想想,繼續調整正規表示式:
function format_amount($amount){ return preg_replace('/(\d)(?=(\d{3})+\.)/', '$1,', $amount); }
上面格式化檔案位元組大小的時候我們是匹配的3的倍數個數字直到字元結尾,這裡因為是到小數點,所以我們只需要把字元結尾 $ 改為 \. 即可。
仔細看看上面三個正規表示式替換的函式,我們又可以發現它們的共同點:
- 需要找到一個數字,並在這個數字的後面新增一個符號
- 這個數字都有相同的規律,後面的數字的長度都是某一個長度的倍數,直到一個不為數字的字元結束
- 在找到的這些數字的後面新增的符號都是一樣的
有了上面這些條件,我們就可以把上面的三個函式改寫成一個函式:
/** * 從右往左根據指定的位數往一段數字中插入指定的符號 * @param string $number 要分隔的數字字串 * @param integer $b 分隔的位數 * @param string $d 分隔符 * @return string 分隔後的字串 */ function format_number($number, $b = 3, $d = ','){ return preg_replace('/(\d)(?=(\d{' . $b . '})+(?!\d))/', '$1' . $d, $number); } echo format_number('1234567890'); //1,234,567,890 echo format_number('12345678.90'); //12,345,678.90 echo format_number('13888888888', 4, '-'); //138-8888-8888
這樣,我們需要格式化的資料就可以通過這一個函式搞定了。
以上只是我個人的一些思路,如果哪位童鞋還有更好的方法,歡迎交流!!!
評論(4)