2014年12月2日 星期二

RUBY,大寫數字轉小寫數字,國字數字轉阿拉伯數字

RUBY,大寫數字轉小寫數字,國字數字轉阿拉伯數字

今天,我在處理中文地址的時候,發現有人的門牌號碼填國字,譬如中正路四三號,也有人會填中正路43號,當然沒人是填中正路肆參號,反正程式邏輯是一樣的。(本方法忽略四十三->43這種格式,若有必要,請自行寫程式判定京兆億萬千百十出現的位置,是否合理,然後再進行轉換)

一般想到的就是把字串裡面每個字遍尋一遍,然後寫個switch,對出現的字元進行轉換,譬如:

// psudo code
for each character in string
    switch(character)
    case: '一'
        convert_to(1)
    case: '二'
        convert_to(2)
        .
        .
        .
    case: '九'
        convert_to(9)
    end
end

但其實你使用的是Ruby語言的話,其實Ruby語言有提供一個很簡潔的方法string.tr(from_str, to_str)

使用的方式是這樣子的,提供兩個字串,兩個字串相對應的位置會互相轉換,譬如提供兩個字串:

#輸入字串1
'abc'
#輸入字串2
'123'

則會將a變為1, b變為2, c變為3,舉個實際例子:

"xx_abc_xx".tr('abc', '123')
# 輸出 "xx_123_xx"

"xx_ccc_xx".tr('abc', '123')
# 輸出 "xx_333_xx", '1'跟'2'都沒出現?因為呼叫tr的字串裡面也沒有'a'跟'b'呀~

"cba".tr('abc', '123')
# 輸出 "321", 為什麼反過來?因為呼叫tr的字串是'cba'呀~(a變為1, b變為2, c變為3)

上面的例子,是比較快速簡易的應用,兩個輸入的字串長度一樣,對於呼叫tr方法的字串,就會將內容替換掉。那如果要傳入兩個字串不一樣長,譬如第一二個比較長,那多出來的部分則不會用到,譬如:

"abc".tr('ab', '123')
# 輸出"12c", 第二個引數中,那個'3'則不會用到

如果是第一個字串比較長,譬如:

"abc".tr('abc', '12')
# 輸出"122", 第一個引數比第二個引數的長度還要長,則第二個引數比較長沒得對應的部分,直接用第二個引數中,最後一個字元替換

#同理
"abcdefghijk".tr('abcdefg', '12')
# 輸出"1222222hijk"

所以我們將大小寫國字數字轉阿拉伯數字,可以全部用列舉的方舉出來,讓他們一一對應

chinese = "零一二三四五六七八九"
arabic = "0123456789"

"一三五七九".tr(chinese, arabic)
# 輸出 "13579"

# 反過來,也可以用阿拉伯數字轉國字
"98765".tr(arabic, chinese)
#輸出 "九八七六五"

#多個大寫數字
big_chinese = "零壹贰叁肆伍陆柒捌玖"
"壹贰叁肆伍".tr(big_chinese, chinese)
# 輸出"一二三四五"

但這邊有個簡易的寫法,參考Ruby的正規表示式(可以在這個網頁做測試)

輸入引入的部分,如果正規表示式中,使用中括號的用法,例如:

[abc]  # 表示任何abc
[^abc] # 表示任何非abc,注意'^'符號放在中括號內,代表'非',而不是代表開頭字元
[1-9] # 表示任何1到9之間的字元

所以我們數字轉換的例子也可以寫成

chinese = "零一二三四五六七八九"
"一三五七九".tr(chinese, '0-9')
# 輸出 "13579"

就可以直接用'0-9'代表所有的阿拉伯數字,那麼是否也可以用'零-九'來代表所有的國字數字呢?

不行的,因為國字的排序並不像英文字元一樣的排法,你可以這樣測試看看

('零'..'九').each{|c| puts c}
# 沒有印出任何字元

('一'..'九').each{|c| puts c}
#印出 一 丁 丂 七 丄 丅 丆 ... 九

可見國字是用筆劃排序的,所以無法使用'零-九'來代表數字,得一一列舉出來。

所以關於門牌號碼,就可以這樣子處理了,全部轉為阿拉伯數字

address = '中正路四三號'
chinese = "零一二三四五六七八九"

address.tr(chinese, '0-9')
輸出"中正路43號"

同理,也可以玩玩英文大小寫轉換

# 小寫轉大寫,一般寫法
'hello world'.upcase # => "HELLO WORLD"

# 使用tr, 多此一舉一下
'hello world'.tr('a-z', 'A-Z') # => "HELLO WORLD"

沒有留言:

張貼留言