文章目录
项目实战一: 数字转换为各种货币读法
说道字符串的各种转换,其实有各种工具都可以实现。但对于初学者来说,自己亲手去做时,又是另外一回事儿 ? ,写这边博客的目的有三点:
- 第一 , 巩固自身的知识 , 做一个小实例;
- 第二 , 也希望帮到需要帮助的小伙伴 ? ;
- 第三 , 本身水平也有限 , 仍有许多不足之处 , 由于时间仓促 ,还没来得及对代码进行优化 , 希望路过的大牛能指点一二 ? 。
一、 实验环境
1. python 3.0 +以上
2. Windows 操作系统下
二、 实验工具
1. 包括但不限于: pycharm 2019 或者 pycharm 2017
三、所用模块(第三方库)
1. 基础模块 easygui 、time
2. 拓展模块 pywin32 、 pyinstaller
3. * 更多 os 、 sys [用于异常处理时进程的自启]
四、 其他
1. 程序打包 :pyinstaller -F python_programming_name.py
2. 组件 :ccbox()、choicebox()、buttonbox()
功能展示
- 程序已经简单的打包好了,下面展示一下这个还很粗糙的程序 ?
- 1st ? 点击打包好的 .exe 可执行程序
- 2st ? 弹出两个窗口 ,我们先来看一下 第一个功能 : [人民币]
3st 继续进行 ? .
4st 要我们输入数字 ,那就随便一个吧 ? .
很人性的弹出一个询问的选择窗口 ? .
- 5st ? 又回到这个界面了 ,在试试其它的
- Ost ?
- End ? 试一下极端的 :
- 直接敲回车或其它字符
- 其它选项
嗯 ,? 这里就等小伙伴门自己来完善 ,或者添加其它功能(如果感兴趣的话 ?)
到目前为止,界面相对还算友好的
一、思路分析
中所周知,完成一件简单的事情,只要有想法,即时便可以;但是要做好一件相对复杂的事情,光有想法还不够,地球上几十亿人,有相同想法或者相似的想法何止你一个,但是有能力、有需求、并将之付诸行动的没有多少(相对于庞大的人口基数)。更何况是做一个项目。因此,我们需要有计划地按照我们的思路来一步步进行。
(一)、需求分析
初学者用于练习、巩固基础知识。包括但不限于:逻辑,语法,基本的函数定义、类定义及调用 ,常用模块的安装、导入和使用,小实例的准备和实现方法与步骤 ,debug等。
(二)、功能
(未完成的可按照已完成的进行相应拓展)
功能一 :转换为 [RMB] 读法
- 将数字转换为RMB的阿拉伯数字和大写读法【单位:元】
- 将数字将数字转换为RMB的阿拉伯数字和大写读法【单位:万元】
- 将数字将数字转换为RMB的阿拉伯数字和大写读法【单位:亿元】
功能二 :转换为 [US$] 读法
- 将数字将数字转换为US$的阿拉伯数字和大写读法【单位:美元】
- 将数字将数字转换为US$的阿拉伯数字和大写读法【单位:千美元】
- 将数字将数字转换为US$的阿拉伯数字和大写读法【单位:百万美元】
- 将数字将数字转换为US$的阿拉伯数字和大写读法【单位:十亿美元】
(三)、思路
-
第一 ,将从键盘接收的信息进行格式化,处理为所需要的数据。( input()接收的是字符串 )
直接用float()强制转换便可
-
第二 ,将整数和小数部分进行分离。(因为读法有所差异)
这两步相对容易很多,用int()直接将这个浮点数强制类型转换成一个整数,得到我们所需的整数部分;再用作差法,[浮点数] - [整数部分] = [小数部分]。
出于习惯,都是保留两位小数,多余的意义不大。这里将用到round(),这样会产生一些小问题,将在实例中进行细说。
-
第三 ,将各位的数据进行分离,依次转换为大写的中文格式数字,并在相应位置加上单位。
我在这里用 迭代法 进行意义置换
那么如何加上单位呢 ,不难发现,中国的读法习惯是 每隔四位为一个单元 ,即 :万 、亿 。这样一来,思路更加清晰了,将整数划分为三个部分 (在以【元】为单位只考虑12位的情况,以【万元】和【亿元】为单位是类似,相应处理后的整数部分都应不多于12位)
如果这节 4 位数字出现在 1~4 位,则后面添加单位“元”;
如果这节 4 位数字出现在 5~8 位,则后面添加单位“万”;
如果这节 4 位数字出现在 9~12 位,则后面添加单位“亿”;我们在实现的时候便可以把其以4位为一个节点进行转换。
二、实现功能
这里 , 我把每个功能都定义为一个单独的类,在类里进行实现 。
类可以起到模板的作用,因此,可以在创建实例的时候,把一些我们认为必须绑定的属性强制填写进去。
即:
class class_name(object):
# 说明 :与python2不同的是,其实在python3中,class()是默认继承object()的
# 这里为规范 和 清晰思路(初学)考虑而这样写
- 每个类都继承了 object 。
为什么要继承object类呢?目的是便于统一操作。继承object类是为了让自己定义的类拥有更多的属性。- 主要区别:
class_name()类不继承object,则只拥有 doc, module 和自定义的 name 变量,这个类的命名空间只有三个对象可以操作。
class_name()类继承了object,拥有了更多的可操作的对象,这些都是类中的高级特性。如:
[
class , delattr , dict , doc , format , getattribute,
hash , init , module , new , reduce , reduce_ex , repr ,
setattr , sizeof , str , subclasshook , weakref , name
]
(一)、结构框架
其他申明:
- 关于__init__方法,它的第一个参数永远是self,表示创建的实例本身,因此,在__init__方法内部,可以把各种属性绑定到self,这样self就指向创建的实例本身。有了__init__方法,在创建实例的时候,就不能传入空的参数了,必须传入与__init__方法匹配的参数,但self不需要传,Python解释器自己会把实例变量传进去:
- 和普通的函数相比,在类中定义的函数只有一点不同,就是第一个参数永远是实例变量self,并且,调用时,不用传递该参数。除此之外,类的方法和普通函数没有什么区别,所以,你仍然可以用默认参数、可变参数、关键字参数和命名关键字参数。
# 1、将数字转换为RMB的阿拉伯数字和大写读法【单位:元】
class rmb_ShuYuan_Transform(object):
def __init__(self):
pass
def isolate(self,num):
pass
def four_to_hanstr(self,num_str):
pass
def fraction_to_str(self,num_str):
pass
def integer_to_str(self,num_str):
pass
def main(self):
pass
# 2、将数字将数字转换为RMB的阿拉伯数字和大写读法【单位:万元】
class rmb_ShuWanYuan_Transform(object):
pass
# 3、将数字将数字转换为RMB的阿拉伯数字和大写读法【单位:亿元】
class rmb_ShuYiYuan_Transform(object):
pass
# 4、将数字将数字转换为US$的阿拉伯数字和大写读法【单位:美元】
class US_NumDollars_Transform(object):
pass
# 5、 将数字将数字转换为US$的阿拉伯数字和大写读法【单位:千美元】
class US_NumThousandDollars_Transform(object):
pass
# 8、将数字将数字转换为US$的阿拉伯数字和大写读法【单位:百万美元】
class US_NumMillionDollars_Transform(object):
pass
# 9、 将数字将数字转换为US$的阿拉伯数字和大写读法【单位:十亿美元】
class US_NumBillionDollars_Transform(object):
pass
# 10、类的调用功能
def Menu():
pass
(二)、具体实现
功能一 、转换为 [RMB] 读法
- 1. 定义 【数值—>[元] 人民币】(RMB) 的类 :rmb_ShuYuan_Transform(object)
class rmb_ShuYuan_Transform(object):
# 这里是具体方法(函数)
rmb_ShuYuan_Spider = rmb_ShuYuan_Transform()
# rmb_ShuYuan_Spider.main() # 进行单独测试时 , 可自行去掉注释符号 [#] ,调用里面的 main()
-
定义 __init __ () 方法, 将其中的属性绑定到self , 在同一个类中通过self进行调用
初始化han_list[](中文大写数字) 、 unit_list[](4字节划分单位) 两个列表
def __init__(self): self.han_list = ["零", "壹", "贰", "叁", "肆", \ "伍", "陆", "柒", "捌", "玖"] self.unit_list = ["十", "百", "千"]
- 定义 isolate() 方法,将接收到的信息进行格式化
说明
- 主要功能 :
分离出输入的浮点数的 [整数部分] 和 [小数部分]
- 处理方法 :
利用 int() 强制类型转换 和 作差法
- 处理结果 :
返回两个值(字符串),integer(整数部分) 和 fraction(小数部分[经 过处理后的整数]) 。
def isolate(self,num): integer = int(num) a_num = (num - integer) * 100 b_num = int(a_num) if b_num == 99 and a_num - b_num >= 0.5: # 处理小数四舍五入到整数部分的bug,方法不止一种,欢迎留言讨论^_^ integer += 1 fraction = 0 else: # 浮点数减去整数部分,得到小数部分,小数部分乘以100后再取整得到2位小数 fraction = round((num - integer) * 100) # 等同于int(num - integer) ## 这一句会有bug, 它不能处理小数部分四舍五入到整数部分,所以在前面加了if语句处理 if fraction == 0: fraction = "" # 确保本身输入的没有小数,而在分离的时候产生多余的“0”(其实仍然有问题,比如本身输入的是一个小数) # 下面把整数转换为字符串 return (str(integer), str(fraction))
- 定义 four_to_hanstr() 方法,将接收到的信息进行大小写的转换
说明
- 主要功能 :
把一个四位 [数字字符串] 的变成 [汉字字符串]
- 处理方法 :
利用 for 迭代
- 处理结果 :
返回 result(大写数字字符串)。
def four_to_hanstr(self,num_str): # 这里的四位其实不是这里的,是传进来的的num_str参数是一个四位或更少的数值;或者说是调用的时候处理的是四位或更少的数值 result = "" num_len = len(num_str) # 依次遍历数字字符串的每一位数字 for i in range(num_len): # 把字符串转成数值 num = int(num_str[i]) # 如果不是最后一位数字,而且数字不是零,则需要添加单位(千、百、十) if i != num_len - 1 and num != 0: result += self.han_list[num] + self.unit_list[num_len - 2 - i] # 否则不要添加单位 else: result += self.han_list[num] return result
- 定义 fraction_to_str() 方法, 处理接收到的 小数部分 ,将其进行【阿拉伯数字–>中文大写数字】的转换 , 在相应位置附上单位
说明
- 主要功能 :(以角(分)为单位进行转换:)
若小数部分存在,则将其转换为RMB大写格式,加上货币单位,并返回;
否则,返回“整”
- 处理方法 :
利用 [if] 、[elif] 及 [if 语句的 嵌套]
- 处理结果 :
返回 result(大写数字字符串+单位)。
def fraction_to_str(self,num_str): # 单位 角、分 str_len = len(num_str) # 注:num_str中的数据是字符串格式 if str_len == 0: """" 这个条件似乎是多余的,因为尽管传进来的的是整数,但是在做整数和小数分离的过程会产生“0”, 进而其小数长度必定不为“0”。 解决:(其实也不存在解决,因为本身也没有多大问题,只是让你更清楚,让结构更加完整) 在定义函数isolate()时加入,if fraction == 0:fraction = "" , 确保本身输入的没有小数,而在分离的时候产生多余的“0” """ return "整" elif str_len == 1: if num_str != "0": return self.four_to_hanstr(num_str) + "角" else: return "整" elif str_len == 2 and num_str[-1] == "0": return \ self.four_to_hanstr(num_str[0]) + "角" else: return \ self.four_to_hanstr(num_str[0]) + "角" + \ self.four_to_hanstr(num_str[-1]) + "分"
- 定义 integer_to_str() 方法, 处理接收到的 整数部分,将其进行【阿拉伯数字–>中文大写数字】的转换 , 在相应位置附上单位
说明
- 主要功能 :(以元(¥)为单位进行转换:)
将整数部分的数字字符串变成汉字字符串
- 处理方法 :
利用 [if] 、[elif] 及 [if 语句的 嵌套]
- 处理结果 :
返回 result(大写数字字符串+单位)。
def integer_to_str(self,num_str): # 单位元 str_len = len(num_str) if str_len > 12: print("\n###>该数字超出计量范围!<###\n请重新输入整数部分为12(包含)以内的数字\n") self.main() return # 如果大于8位,包含单位亿 elif str_len > 8: return self.four_to_hanstr(num_str[:-8]) + "亿 " + \ self.four_to_hanstr(num_str[-8: -4]) + "万 " + \ self.four_to_hanstr(num_str[-4:]) + "元 " # 如果大于4位,包含单位万 elif str_len > 4: return self.four_to_hanstr(num_str[:-4]) + "万 " + \ self.four_to_hanstr(num_str[-4:]) + "元 " else: return self.four_to_hanstr(num_str) + "元 "
- 定义 main() 方法,主函数
def main(self): # ---进行测试--- # 从键盘输入一个数字(字符串) num = float(input("请从键盘输入一个数字: ")) # 调用函数divide(),将输入的的[整数、浮点数](字符串)分解成整数部分和小数部分 integer, fraction = divide(num) #调用函数integer_to_str()将支持范围内的整数转换为大写并附上货币单位; transform_integer = integer_to_str(integer) #调用函数fraction_to_str()将小数部分(若存在)转换为大写并附上货币单位 transform_fraction = fraction_to_str(fraction) print("\t\t货币类型:","RMB") print("小写格式:",integer + "." + fraction ,"¥") print("大写格式:",transform_integer + transform_fraction)
- 测试
先看一下这一部分的效果效果如何 :
[测试 1 ]: 输入123.56
没问题 ?
[测试 2 ]: 输入44885.786
没问题 ?
[测试 3 ]: 输入885522449.883
没问题 ?
[测试 4 ]: 输入1122334455660.1
gg思密达 ? ,这里是不是跟自己预想的不一样?
按照之前的设定,如果超出表示范围,直接打印【超出范围】的字符串,而不是报错吧 。具体如 何处理 ,将在【三、拓展与部分优化】详细说明。
给出的 [源码] 并不会有提到的问题 ❤️除此之外,其实还有个小问题,就是小数部分四舍五入,即0.99x ,当x>5时。进位 “1” 被丢弃 , 显示 0.100
我们来测试一下:
果真如此。 ? ,对于这个问题,我做了如下的改进:def isolate(self,num): # 将一个浮点数(字符串)强制类型转换为int型,即得到它的整数部分 integer = int(num) # <改进从这里开始> ******************************************* a_num = (num - integer) * 100 b_num = int(a_num) if b_num == 99 and a_num - b_num >= 0.5: # 处理小数四舍五入到整数部分的bug,方法不止一种,欢迎留言讨论^_^ integer += 1 fraction = 0 else: # 浮点数减去整数部分,得到小数部分,小数部分乘以100后再取整得到2位小数 fraction = round( (num - integer) * 100) # 等同于int(num - integer) ## 这一句会有bug, 它不能处理小数部分四舍五入到整数部分,所以在前面加了if语句处理 # <改进到这来结束> ***************************************************************************** if fraction == 0: fraction = "" # 确保本身输入的没有小数,而在分离的时候产生多余的“0”(其实仍然有问题,比如本身输入的是一个小数) # 下面把整数转换为字符串 return (str(integer), str(fraction))
改进说明:
- 处理方法:当遇到需要小数进位到整数的情况 ,通过 if 语句判断 ,符号进位条件 ,则变量重新赋为新值, 当不满足时,触发 else 语句 ,则按照原先的编写即可。
下面进行测试:
哈 ? ,完美解决。
class rmb_ShuYuan_Transform(object):
def __init__(self):
self.han_list = ["零" , "壹" , "贰" , "叁" , "肆" ,\
"伍" , "陆" , "柒" , "捌" , "玖"]
self.unit_list = ["十" , "百" , "千"]
def isolate(self,num):
# 将一个浮点数(字符串)强制类型转换为int型,即得到它的整数部分
integer = int(num)
a_num = (num - integer) * 100