Python實(shí)現(xiàn)將中文大寫金額轉(zhuǎn)數(shù)字金額
在日常的財務(wù)處理、票據(jù)識別或金融系統(tǒng)開發(fā)中,我們常常需要將中文大寫的金額轉(zhuǎn)換為阿拉伯?dāng)?shù)字形式。例如:
- “壹佰元整” → “100”
- “壹仟貳佰叁拾肆元伍角陸分” → “1234.56”
- “壹拾陸萬元” → “160000”
這類需求在銀行票據(jù)OCR識別、合同金額處理等場景中非常常見。本文將詳細(xì)介紹如何使用 Python 編寫一個能夠準(zhǔn)確識別并轉(zhuǎn)換中文大寫金額的函數(shù),并通過對比驗(yàn)證其準(zhǔn)確性。
一、中文大寫金額規(guī)則簡介
中文大寫金額由以下部分組成:
數(shù)字部分(0~9):
零 壹 貳 叁 肆 伍 陸 柒 捌 玖
單位部分:
拾 佰 仟 萬 億
小數(shù)單位:
角 分
特殊標(biāo)記:
- “元”:整數(shù)部分結(jié)束標(biāo)志
- “整”:表示無角分
- “零”:表示中間有空位
二、Python 實(shí)現(xiàn)思路解析
1. 映射關(guān)系定義
我們首先定義兩個字典,分別用于映射中文數(shù)字和單位到對應(yīng)的數(shù)值:
num_map = {
'零': 0, '壹': 1, '貳': 2, '叁': 3, '肆': 4,
'伍': 5, '陸': 6, '柒': 7, '捌': 8, '玖': 9
}
unit_map = {
'拾': 10, '佰': 100, '仟': 1000,
'萬': 10000, '億': 100000000
}
2. 預(yù)處理輸入字符串
去除多余的空格與“整”字,便于后續(xù)解析:
capital = capital.replace(' ', '').replace('整', '')
3. 分離整數(shù)與小數(shù)部分
根據(jù)“元”分割出整數(shù)部分與角分部分:
if '元' in capital:
parts = capital.split('元')
yuan_part = parts[0]
jiao_fen_part = parts[1] if len(parts) > 1 else ''
else:
yuan_part = capital
4. 解析整數(shù)部分
核心邏輯是逐字符遍歷,遇到數(shù)字則記錄臨時值,遇到單位則進(jìn)行乘法運(yùn)算:
def parse_section(s):
if not s:
return 0
if s == '拾': # 特殊情況:"拾"表示10
return 10
result = 0
temp = 0
for char in s:
if char in num_map:
temp = num_map[char]
elif char in unit_map:
result += temp * unit_map[char]
temp = 0
result += temp
return result
5. 處理“億”和“萬”的層級結(jié)構(gòu)
遞歸處理“億”和“萬”的分層結(jié)構(gòu):
def parse_amount(s):
if '億' in s:
parts = s.split('億')
yi_part = parts[0]
rest_part = parts[1] if len(parts) > 1 else ''
value = parse_section(yi_part) * 100000000
if rest_part:
value += parse_amount(rest_part)
return value
elif '萬' in s:
parts = s.split('萬')
wan_part = parts[0]
rest_part = parts[1] if len(parts) > 1 else ''
value = parse_section(wan_part) * 10000
if rest_part:
value += parse_section(rest_part)
return value
else:
return parse_section(s)
6. 角分處理
處理角分部分,支持“角”、“分”、“角分”三種組合:
def parse_jiao_fen(jf):
if not jf:
return ""
jiao = 0
fen = 0
if '角' in jf and '分' in jf:
parts = jf.split('角')
if parts[0] in num_map:
jiao = num_map[parts[0]]
fen_part = parts[1].replace('分', '')
if fen_part in num_map:
fen = num_map[fen_part]
elif '角' in jf:
jiao_part = jf.replace('角', '')
if jiao_part in num_map:
jiao = num_map[jiao_part]
elif '分' in jf:
fen_part = jf.replace('分', '')
if fen_part in num_map:
fen = num_map[fen_part]
if jiao > 0 and fen > 0:
return f".{jiao}{fen}"
elif jiao > 0:
return f".{jiao}0"
elif fen > 0:
return f".0{fen}"
else:
return ""
三、完整代碼示例
def convert_capital_to_small(capital):
num_map = {
'零': 0, '壹': 1, '貳': 2, '叁': 3, '肆': 4,
'伍': 5, '陸': 6, '柒': 7, '捌': 8, '玖': 9
}
unit_map = {
'拾': 10, '佰': 100, '仟': 1000,
'萬': 10000, '億': 100000000
}
capital = capital.replace(' ', '').replace('整', '')
if not capital or capital == '零元':
return '0'
yuan_part = capital
jiao_fen_part = ''
if '元' in capital:
parts = capital.split('元')
yuan_part = parts[0]
if len(parts) > 1:
jiao_fen_part = parts[1]
else:
yuan_part = capital.replace('整', '')
def parse_section(s):
if not s:
return 0
if s == '拾':
return 10
result = 0
temp = 0
for char in s:
if char in num_map:
temp = num_map[char]
elif char in unit_map:
result += temp * unit_map[char]
temp = 0
result += temp
return result
def parse_amount(s):
if not s:
return 0
if len(s) == 1 and s in num_map:
return num_map[s]
if '億' in s:
parts = s.split('億')
yi_part = parts[0]
rest_part = parts[1] if len(parts) > 1 else ''
value = parse_section(yi_part) * 100000000
if rest_part:
value += parse_amount(rest_part)
return value
elif '萬' in s:
parts = s.split('萬')
wan_part = parts[0]
rest_part = parts[1] if len(parts) > 1 else ''
value = parse_section(wan_part) * 10000
if rest_part:
value += parse_section(rest_part)
return value
else:
return parse_section(s)
yuan_value = parse_amount(yuan_part)
def parse_jiao_fen(jf):
if not jf:
return ""
jiao = 0
fen = 0
if '角' in jf and '分' in jf:
parts = jf.split('角')
if parts[0] in num_map:
jiao = num_map[parts[0]]
fen_part = parts[1].replace('分', '')
if fen_part in num_map:
fen = num_map[fen_part]
elif '角' in jf:
jiao_part = jf.replace('角', '')
if jiao_part in num_map:
jiao = num_map[jiao_part]
elif '分' in jf:
fen_part = jf.replace('分', '')
if fen_part in num_map:
fen = num_map[fen_part]
if jiao > 0 and fen > 0:
return f".{jiao}{fen}"
elif jiao > 0:
return f".{jiao}0"
elif fen > 0:
return f".0{fen}"
else:
return ""
jf_str = parse_jiao_fen(jiao_fen_part)
if jf_str:
return f"{int(yuan_value)}{jf_str}"
else:
return str(int(yuan_value))
四、測試驗(yàn)證
我們可以編寫一個簡單的對比函數(shù)來驗(yàn)證轉(zhuǎn)換結(jié)果是否正確:
def get_dx_compare(capital_amount, small_amount):
try:
capital_to_small = convert_capital_to_small(capital_amount)
small_amount_clean = small_amount.replace(',', '')
converted_float = float(capital_to_small)
expected_float = float(small_amount_clean)
if converted_float == expected_float:
print(f"? 金額匹配:小寫金額 {small_amount}元,大寫金額 {capital_amount}")
return True
else:
print(f"? 金額不匹配:")
print(f" 小寫金額: {small_amount}")
print(f" 大寫金額: {capital_amount}")
print(f" 轉(zhuǎn)換結(jié)果: {capital_to_small}")
return False
except Exception as e:
print(f"轉(zhuǎn)換出錯: {e}")
return False
運(yùn)行測試:
get_dx_compare('壹拾陸萬元', '160000') # ? 應(yīng)該輸出匹配
get_dx_compare('壹萬元', '10000')
get_dx_compare('零元整', '0')
get_dx_compare('壹佰元整', '100')
get_dx_compare('壹仟貳佰叁拾肆元伍角陸分', '1234.56')
輸出結(jié)果如下:
? 金額匹配:小寫金額 160000元,大寫金額 壹拾陸萬元
? 金額匹配:小寫金額 10000元,大寫金額 壹萬元
? 金額匹配:小寫金額 0元,大寫金額 零元整
? 金額匹配:小寫金額 100元,大寫金額 壹佰元整
? 金額匹配:小寫金額 1234.56元,大寫金額 壹仟貳佰叁拾肆元伍角陸分
五、總結(jié)
本文提供了一個較為完整的中文大寫金額轉(zhuǎn)阿拉伯?dāng)?shù)字的 Python 實(shí)現(xiàn)方案,涵蓋以下關(guān)鍵點(diǎn):
- 數(shù)字與單位映射
- 整數(shù)部分層級解析(億、萬、千、百、十)
- 角分部分精確處理
- 輸入預(yù)處理(去空格、去“整”)
- 結(jié)果驗(yàn)證機(jī)制
你可以將其用于金融系統(tǒng)中的金額校驗(yàn)、OCR識別后處理、合同文本解析等場景。
以上就是Python實(shí)現(xiàn)將中文大寫金額轉(zhuǎn)數(shù)字金額的詳細(xì)內(nèi)容,更多關(guān)于Python金額大寫轉(zhuǎn)數(shù)字的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python3如何使用range函數(shù)替代xrange函數(shù)
這篇文章主要介紹了Python3如何使用range函數(shù)替代xrange函數(shù),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-10-10
Python實(shí)現(xiàn)重建二叉樹的三種方法詳解
這篇文章主要介紹了Python實(shí)現(xiàn)重建二叉樹的三種方法,結(jié)合實(shí)例形式分析了Python重建二叉樹的實(shí)現(xiàn)方法、操作技巧與注意事項(xiàng),需要的朋友可以參考下2018-06-06

