将阿拉伯数字金额转换为人民币大写形式
Humoon / 2019-10-11
本程序理论上可以转换任意位数,但由于 R 语言储存数据的精度问题,当包含角、分时,只能转换百万亿人民币以下数量级的金额数。
library(tidyverse)
## -- Attaching packages --------------------------------------- tidyverse 1.3.1 --
## v ggplot2 3.3.5 v purrr 0.3.4
## v tibble 3.1.3 v dplyr 1.0.7
## v tidyr 1.1.3 v stringr 1.4.0
## v readr 2.0.0 v forcats 0.5.1
## -- Conflicts ------------------------------------------ tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag() masks stats::lag()
library(data.table)
##
## 载入程辑包:'data.table'
## The following objects are masked from 'package:dplyr':
##
## between, first, last
## The following object is masked from 'package:purrr':
##
## transpose
han_list = c("零" , "壹" , "贰" , "叁" , "肆", "伍" , "陆" , "柒" , "捌" , "玖")
# 划分整数和小数部分的函数
divide <- function(num){
integer <- floor(num)
fraction <- round((num - integer)*100)
c(integer, fraction) %>% return()
}
# 输出小数部分的函数
fraction_to_rmb <- function(fraction){
a <- fraction %/% 10
b <- fraction %% 10
if (a^2 + b^2 == 0) {
return('整')
} else if (a == 0 & b != 0) {
return(str_c('零', han_list[b + 1], '分'))
} else if (a != 0 & b == 0) {
return(str_c(han_list[a + 1], '角'))
} else {
return(str_c(han_list[a + 1], '角', han_list[b + 1], '分'))
}
}
# 输出整数部分的函数
integer_to_rmb <- function(integer){
string <- integer %>% as.character()
n <- str_length(string)
m <- (n + 7)/8 # 8位一组来操作,拆分成 m 组
s <- ''
for (i in 1:m) {
if (i < m) {
s[i] <- str_sub(string, -8*i, (7 - 8*i)) %>%
eight_to_rmb()
} else {
s[i] <- str_sub(string, 1, (7 - 8*m)) %>%
eight_to_rmb()
}
}
# 将每组返回的字符串连接起来
rmb <- ''
for (i in m:1) {
rmb <- str_c(rmb, s[i])
}
# 用正则表达式处理连续的多个零
rmb <- rmb %>% str_replace_all('零+','零') %>% # 连续多个零变成一个
str_replace_all('零万', '万') %>% # 万和亿前的末位零删掉
str_replace_all('零亿', '亿') %>%
str_replace('^壹什', '什') %>% # 开头不会读作“壹什”
str_sub(1, -2) # 去掉个位的“亿”
return(rmb)
}
## 处理8位数字的函数
eight_to_rmb <- function(string){
n <- str_length(string)
if (n == 8) { # 8位满时
front <- str_sub(string, 1, 4) #前4位
behind <- str_sub(string, 5, 8) # 后4位
if (str_sub(string, 1, 8) == '00000000') {
return('零') # 8位皆0不要“亿”
} else if (front == '0000') {
return(str_c('零', four_to_rmb(behind), '亿')) # 4位皆0不要“万”
} else {
return(str_c(four_to_rmb(front), '万', four_to_rmb(behind), '亿'))
}
} else if (n > 4) { # 不足8位(数字最前的若干位)
front <- str_sub(string, 1, n - 4)
behind <- str_sub(string, n - 3, n)
return(str_c(four_to_rmb(front), '万', four_to_rmb(behind), '亿'))
} else {# 不足4位
return(str_c(four_to_rmb(string), '亿'))
}
}
## 处理4位数字的函数
four_to_rmb <- function(string){
n <- str_length(string)
s <- ''
for (i in 1:n) {
s[i] <- str_sub(string, i, i)
}
dt <- tibble(seq = n:1, num = s) %>% setDT()
dt[, han_character := han_list[num %>% as.integer() + 1]] # 中文大写
dt[, magnitude := ''] # 单位
dt[seq == 2, magnitude := '什']
dt[seq == 3, magnitude := '佰']
dt[seq == 4, magnitude := '仟']
dt[num == '0', magnitude := ''] # 数字为0时,十百千单位要去掉
# 组合数字与单位
dt[, rmb := str_c(han_character, magnitude)]
return(dt$rmb %>% str_c(collapse = ''))
}
## 主体函数
main <- function(float_money){
# 首先将金额分为整数部分和小数部分
integer <- divide(float_money)[1]
fraction <- divide(float_money)[2]
# 用两个函数分别处理整数分布和小数部分
rmb <- str_c(integer_to_rmb(integer),
'圆',
fraction_to_rmb(fraction))
cat(rmb)
}
main(202000012345678.09)
## 贰佰零贰万亿壹仟贰佰叁什肆万伍仟陆佰柒什捌圆零玖分
main(202000012345678.00)
## 贰佰零贰万亿壹仟贰佰叁什肆万伍仟陆佰柒什捌圆整
main(202000002305008.09)
## 贰佰零贰万亿零贰佰叁什万伍仟零捌圆零玖分