這幾天做一個(gè)小程序的時(shí)候有了這樣的需求:把阿拉伯?dāng)?shù)字轉(zhuǎn)換成漢字,比如把‘101’轉(zhuǎn)換成‘一百零一’,把‘10000’轉(zhuǎn)換成‘一萬(wàn)’。?
做這樣的程序的時(shí)候有以下幾個(gè)技術(shù)難點(diǎn):?
? 1.加單位問(wèn)題:比如需要加入‘十‘’百‘’千‘’萬(wàn)’?
? 2.去掉多余的‘零’的問(wèn)題:因?yàn)闈h語(yǔ)中超過(guò)兩個(gè)單位為‘0‘,我們只會(huì)說(shuō)一個(gè)‘零’。而且如果末尾位次也是零,則什么都不讀。比如‘10001’讀作‘一萬(wàn)零一’,而‘10000’就直接讀作‘一萬(wàn)’。?
? 3.保留較大單位的問(wèn)題:在去零的過(guò)程中,我們需要保留‘萬(wàn)’、‘億’這種單位,但是‘百’‘千’等就不需要。??
?為了解決問(wèn)題,我設(shè)計(jì)了兩套編程思路(不用現(xiàn)成庫(kù)的情況):?
? 1.采用字符串替換法:?
? ? 第一步:把原來(lái)的數(shù)字str()再list(),用漢字‘零一二三四五六七八九’替換‘0123456789’。?
? ? 第二步:在需要的位置加入單位。?
? ? 第三步:刪除多余的單位和零?
? 2.采用數(shù)學(xué)計(jì)算法:?
? ? 第一步:設(shè)計(jì)函數(shù)用原數(shù)字整除對(duì)應(yīng)的10的次方數(shù),比如200000就讓它整除100000。得數(shù)即為對(duì)應(yīng)單位的數(shù)值,比如這個(gè)就是十萬(wàn)位的2。?
? ? 第二步:用原數(shù)字整除后的余數(shù)(%取余運(yùn)算),繼續(xù)和對(duì)應(yīng)的10的次方數(shù)進(jìn)行整除,然后取余……循環(huán)進(jìn)行?
? ? 第三步:在每一次整除后,都把得到的整數(shù)轉(zhuǎn)換為中文并和對(duì)應(yīng)位次的單位的中文連接成字符串。?
? ? 第四步:如果取余后的數(shù)比原數(shù)字小兩位或者以上,字符串連接上一個(gè)‘零’,并跳過(guò)對(duì)應(yīng)單位,理論上不產(chǎn)生多余的‘零’和單位。?
? ? ? ? 有趣的是,方法二是一個(gè)非常有精細(xì)編程思想的做法,而且在實(shí)現(xiàn)的過(guò)程中可以通過(guò)拆分?jǐn)?shù)字(比如把100000拆為10+0000)而進(jìn)一步簡(jiǎn)化程序(只用設(shè)計(jì)千位以內(nèi)的程序即可,千以上的算完加個(gè)‘萬(wàn)’就好),對(duì)于多余‘零’的產(chǎn)生控制上可以說(shuō)也是極其優(yōu)秀,除了末尾外根本不會(huì)多出來(lái)沒(méi)用的‘零’和‘單位’。?
? ? ? ?但是方法一,卻是一個(gè)很符合python思想的辦法:雖然會(huì)產(chǎn)生不計(jì)其數(shù)的多余‘零’和單位,但是在計(jì)算的過(guò)程中幾乎沒(méi)有用到數(shù)學(xué),都是if或者del這樣的簡(jiǎn)單語(yǔ)句。在最后的多余單位刪除中,可以采用正則表達(dá)式來(lái)提高效率。??
? ? ? ?兩種方法各有優(yōu)缺點(diǎn),對(duì)于兩種變成思路,我分別設(shè)計(jì)了三種程序來(lái)完成任務(wù),并對(duì)它們進(jìn)行計(jì)時(shí),對(duì)比效率:?
? 任務(wù)內(nèi)容:轉(zhuǎn)換1-9999999所有的數(shù)字并產(chǎn)生一個(gè)對(duì)應(yīng)列表。?
? 程序一思路:采用數(shù)學(xué)計(jì)算法,整除對(duì)應(yīng)10的次方數(shù)+取余,把整除得數(shù)轉(zhuǎn)換成字符串,加上對(duì)應(yīng)單位數(shù),再次進(jìn)行。如果余數(shù)和原數(shù)字差兩位且不是零,則輸出一個(gè)‘零’并連接。?
? 程序二思路:采用字符串法并應(yīng)用正則表達(dá)式,先把原數(shù)字打成列表?
? 用漢字替換所有數(shù)字并在對(duì)應(yīng)位次插入單位。如果對(duì)應(yīng)位次漢字是‘零’,則不插入單位,改為再插入一個(gè)‘零’。之后用正則表達(dá)式識(shí)別‘零’+并替換為‘零’,再刪除末尾‘零’后返回字符串。?
? 程序三思路:采用純字符串方法。先把原數(shù)字打成列表用漢字替換數(shù)字并插入單位。將列表倒置,在列表內(nèi)搜索‘零’,再驗(yàn)證找到位置處i后面兩位[i+2]處是否為單位或者‘零’,如果是,則刪除[i+1],之后遞歸。這樣的話零以后的所有多余單位和零就全部被刪除了。然后進(jìn)行搜索,刪除所有‘零’左邊的一位[i-1](就是它原有對(duì)應(yīng)的單位),之后再刪除末尾的‘零’即可。?
不廢話,上代碼:?
程序一:?
num=['零','一','二','三','四','五','六','七','八','九']
k=['零','十','百','千','萬(wàn)','十','百']
import time
def rankid():
? ? rank=[]
? ? for i in range(9999999):
? ? ? ? a=tstr(i)
? ? ? ? rank.append(a)
? ? return rank
#取整取余并連接,返回連接好的字符串和余數(shù)
def turn(x,y):
? ? if y>= 1:
? ? ? ? a=x//pow(10,y)
? ? ? ? b=x%pow(10,y)
? ? ? ? c=num[a]+k[y]
? ? ? ? if y>4 and b<pow(10,4):
? ? ? ? ? ? c+=k[4]
? ? ? ? if (len(str(x))-len(str(b))) >= 2 and b != 0:
? ? ? ? ? ? c+=k[0]
? ? else:
? ? ? ? a=x
? ? ? ? b=0
? ? ? ? c=num[a]
? ? return (c,b,)
#調(diào)用上一個(gè)函數(shù),以保證進(jìn)行完所有的數(shù)并返回
def tstr(x):
? ? c=turn(x,(len(str(x))-1))
? ? a=c[0]
? ? b=c[1]
? ? while b != 0:
? ? ? ? a+=turn(b,(len(str(b))-1))[0]
? ? ? ? b=turn(b,(len(str(b))-1))[1]
? ? return a
start=time.time()
ranki=rankid()
end=time.time()-start
print('程序共用時(shí):%0.2f'%end)
共用時(shí):362.93?
程序很精巧,可惜太慢。??
程序二:?
import re,time
#主程序
def ranki():
? ? rank=[]
? ? for i in range(9999999):
? ? ? ? i=turn(i)
? ? ? ? rank.append(i)
? ? return rank
#如果超過(guò)萬(wàn),則分為兩部分以節(jié)約代碼和運(yùn)行速度
def turn(x):
? ? i=str(x)
? ? if len(i) >4:
? ? ? ? i=tran(i[0:-4])+'萬(wàn)'+tran(i[-4:])
? ? else:
? ? ? ? i=tran(i[-4:])
? ? return i
#轉(zhuǎn)換數(shù)字并插入對(duì)應(yīng)單位,單位為‘零’則再插入一個(gè)‘零’以方便正則表達(dá)式替換
def tran(x):
? ? num=['零','一','二','三','四','五','六','七','八','九']
? ? kin=['零','十','百','千']
? ? x=list(reversed(x))
? ? for i in x:
? ? ? ? x[(x.index(i))]=num[int(i)]
? ? if len(x) >= 2:
? ? ? ? if x[1]==num[0]:
? ? ? ? ? ? x.insert(1,kin[0])
? ? ? ? else:
? ? ? ? ? ? x.insert(1,kin[1])
? ? ? ? if len(x) >= 4:
? ? ? ? ? ? if x[3]==num[0]:
? ? ? ? ? ? ? ? x.insert(3,kin[0])
? ? ? ? ? ? else:
? ? ? ? ? ? ? ? x.insert(3,kin[2])
? ? ? ? ? ? if len(x) >= 6:
? ? ? ? ? ? ? ? if x[5]==num[0]:
? ? ? ? ? ? ? ? ? ? x.insert(5,kin[0])
? ? ? ? ? ? ? ? else:
? ? ? ? ? ? ? ? ? ? x.insert(5,kin[3])
? ? x=delz(x)
? ? return x
#進(jìn)行多余‘零’的刪除
#reversed()函數(shù)真是可以用在列表和字符串。
#加上 if 語(yǔ)句 防止對(duì)不必要的數(shù)據(jù)進(jìn)行正則表達(dá)式檢測(cè)
def delz(x):
? ? x=''.join(x)
? ? if '零零'in x:
? ? ? ? x=re.sub('零+','零',x)
? ? if x.startswith('零'):
? ? ? ? x=list(x)
? ? ? ? x.remove('零')
? ? x=reversed(x)
? ? x=''.join(x)
? ? return x
start=time.time()
rank=ranki()
end=time.time()-start
print('程序共用時(shí):%0.2f'%end)
共用時(shí):181.69s
是第一個(gè)的兩倍快。?
程序三:?
num=['零','一','二','三','四','五','六','七','八','九']
kin=['十','百','千','萬(wàn)','零']
import time
def sadd(x):
? ? x.reverse()
? ? if len(x) >= 2:
? ? ? ? x.insert(1,kin[0])
? ? ? ? if len(x) >= 4:
? ? ? ? ? ? x.insert(3,kin[1])
? ? ? ? ? ? if len(x) >= 6:
? ? ? ? ? ? ? ? x.insert(5,kin[2])
? ? ? ? ? ? ? ? if len(x) >= 8:
? ? ? ? ? ? ? ? ? ? x.insert(7,kin[3])
? ? ? ? ? ? ? ? ? ? if len(x) >= 10:
? ? ? ? ? ? ? ? ? ? ? ? x.insert(9,kin[0])
? ? ? ? ? ? ? ? ? ? ? ? if len(x) >= 12:
? ? ? ? ? ? ? ? ? ? ? ? ? ? x.insert(11,kin[1])
? ? x=fw(x)
? ? x=d1(x)
? ? x=d2(x)
? ? x=dl(x)
? ? return x
def rankis():
? ? rank=[]
? ? for i in range(9999999):
? ? ? ? i=list(str(i))
? ? ? ? for j in i:
? ? ? ? ? ? i[(i.index(j))]=num[int(j)]
? ? ? ? i=sadd(i)
? ? ? ? rank.append(i)
? ? return rank
def d1(x):
? ? if '零' in x:
? ? ? ? a=x.index('零')
? ? ? ? if a==0:
? ? ? ? ? ? del x[0]
? ? ? ? ? ? d1(x)
? ? ? ? else:
? ? ? ? ? ? if x[a+2] in ['十','百','千','萬(wàn)','零']:
? ? ? ? ? ? ? ? if x[a+1] != '萬(wàn)':
? ? ? ? ? ? ? ? ? ? del x[a+1]
? ? ? ? ? ? ? ? ? ? d1(x)? ? ?
? ? return x
def d2(x):
? ? try:
? ? ? ? a=x.index('零')
? ? ? ? if x[a-1] in ['十','百','千','零']:
? ? ? ? ? ? del x[a-1]
? ? ? ? ? ? d2(x[a+1])
? ? except:pass
? ? return x
def fw(x):
? ? if len(x) >= 9:
? ? ? ? if x[8] == '零':
? ? ? ? ? ? del x[8]
? ? return x
def dl(x):
? ? try:
? ? ? ? if x[0]=='零':
? ? ? ? ? ? del x[0]
? ? ? ? ? ? del1(x)
? ? except:pass
? ? x.reverse()
? ? x=''.join(x)
? ? return x
start=time.time()
rank=rankis()
end=time.time()-start
print('程序共用時(shí):%0.2f'%end)
程序用時(shí):123.68s
雖然還有些多余代碼,但是運(yùn)行速度真是驚人。??
總結(jié):個(gè)人感覺(jué)python是字符串至上的語(yǔ)言,很多地方字符串都能被靈活運(yùn)用,程序還遠(yuǎn)遠(yuǎn)不完美,希望能更快一步。