这题主要麻烦在有很多种情况需要处理:
例子1:100080
将数字由低位到高位划分为以每四位数字为一组:10 0080
应该读yi Shi Wan ling ba Shi
可见若有连续0出现,则只能读一个ling
若末尾有0,则不能读
例子2:1008
将数字由低位到高位划分为以每四位数字为一组:1008
应该读yi Qian ling ba
若有连续0出现,则只能读一个ling
接下来让我们一步步拆解该题:
先用一个字典mp
做映射,将0 ~ 9的数字转换成中文大写形式
由于这个整数最多有9位数字,如果没有9位,则前面补0至9位,n = n.zfill(9)
,方便后续的处理
在Python中,
zfill()
是一个字符串方法(zero fill),用于在字符串的左边填充零(‘0’),直到字符串达到指定的宽度。如果字符串的长度已经等于或超过指定的宽度,则字符串保持不变。这个方法常用于处理数字字符串,特别是当需要将它们格式化为固定长度的字符串时,比如在生成序列号、处理日期时间格式等场景中。举例说明:
假设我们有一个数字字符串
n
,我们想要将其长度填充到9位,不足的部分用零填充在左边。```python
原始数字字符串
n = “123”使用 zfill 方法填充零至长度为9
n_filled = n.zfill(9)输出结果
print(n_filled) # 输出: “000000123”
```在这个例子中,
n
是一个长度为3的字符串"123"
。通过调用n.zfill(9)
,我们在n
的左边填充了6个零,使得新字符串n_filled
的长度为9。如果原始字符串的长度已经等于或超过指定的宽度,则
zfill()
方法不会改变字符串。例如:```python
原始数字字符串
n = “123456789”尝试使用 zfill 方法填充至长度为9(但原字符串已经足够长)
n_filled = n.zfill(9)输出结果
print(n_filled) # 输出: “123456789”(没有改变)
```在这个例子中,
n
已经是一个长度为9的字符串,所以n.zfill(9)
返回的结果仍然是"123456789"
。注意:
zfill()
方法只适用于字符串类型。- 填充的字符是零(‘0’),不能指定其他字符。
- 如果指定的宽度小于字符串的当前长度,则字符串保持不变。
将该9位数分成3部分处理,在下面的代码中的变量名分别体现为high
,mid
,low
,high
代表第一个数字,mid
代表high
后面的4位数字,low
代表mid
后面的四位数字,如123456789,则high = 1,mid = 2345,low = 6789
high = int(str(n[0]))
mid = n[1:5]
low = n[5:]
对high
的处理,如果high == '0'
则置为空串,否则high = mp[high] + ' Yi'
,+ Yi
这个操作是为了连接high
和mid
对mid
的处理:
将mid
列表中这4个数字转换为中文大写形式再加上'Qian'
或'Bai'
或'Shi'
,如果为0则转换为’ling'
q, b, s, w = map(int, mid)
q = mp[q] + ' Qian' if q else 'ling'
b = mp[b] + ' Bai' if b else 'ling'
s = mp[s] + ' Shi' if s else 'ling'
w = mp[w] if w else 'ling'
mid = [q, b, s, w]
去除mid列表末尾的'ling'
:
while mid and mid[-1] == 'ling':
mid.pop() # 去除末尾'ling'
将mid列表中连续的多个'ling'
变成一个'ling'
:
编写一个work
函数处理该操作,因为对low列表同样要进行该操作:
"""
work函数的作用:
将连续的多个'ling'变成一个'ling'
如li = ['ling','ling','er','san','ling','ling','ling','wu']则转换成['ling','er','san','ling','wu']
"""
def work(li):
# 初始化一个变量来存储前一个元素(None,如果还没有元素)
prev_element = None
result = []
for item in li:
# 如果当前元素不是'ling'或者它不是连续出现的'ling'
if item != 'ling' or (item == 'ling' and item != prev_element):
result.append(item)
# 更新前一个元素为当前元素
prev_element = item
return result
由于存在一种可能,亿位(high位为0),并且mid位前几位为0,这种情况要将mid前几位0去掉:
"""
存在一种可能,亿位(high位为0),并且mid位前几位为0,这种情况要将mid前几位0去掉。如这样的数据:100800,在本代码中该数据首先被转换为0 0010 0800
应该读yi Shi Wan ling ba Bai,而不是ling yi Shi Wan ling ba Bai
"""
# 将mid前几位'ling'去掉,由于上面的work操作后,如果前几位有'ling',也只可能是一个'ling'
if high == '' and mid and mid[0] == 'ling':
mid.pop(0) # 去除开头'ling'
if mid and mid != ['ling']: # 判断连接mid和low是否需要添加'Wan'
mid.append('Wan')
else:
mid = []
连接mid和low:
if mid and mid != ['ling']: # 判断连接mid和low是否需要添加'Wan'
mid.append('Wan')
else:
mid = []
接下来就是对low的操作了,对low的操作和mid的操作步骤类似:
将low
列表中这4个数字转换为中文大写形式再加上'Qian'
或'Bai'
或'Shi'
,如果为0则转换为’ling'
去除low
列表末尾的'ling'
将low
列表中连续的多个'ling'
变成一个'ling'
由于存在一种可能,亿位(high位为0),并且mid的4位全为0,这种情况要将low前几位0去掉:
"""
由于存在一种可能,亿位(high位为0),并且mid的4位全为0,这种情况要将low前几位0去掉:
只有当high为0,在代码中体现为空串,mid全为0,在代码中体现为[],这种情况才将low的前面的'ling'删掉,如80,在本代码中该数据首先被转换为0 0000 0080,应该读ba shi
当输入为800000008时,若下面的if语句前面不加上high == '',那么则输出ba Yi ba,这是不对的,正确答案是ba Yi ling ba
"""
# 将low前几位'ling'去掉,由于上面的work操作后,如果前几位有'ling',也只可能是一个'ling'
if high == '' and mid == [] and low and low[0] == 'ling':
low.pop(0) # 去除开头'ling'
将high
,mid
列表,low
列表组合成一个ans
列表,然后再稍微处理下格式就是最后的答案了~
# 将所有部分组合成一个列表ans
ans = [high, *mid, *low]
关于*
运算符的解释:
在Python中,*
运算符用在列表、元组或其他可迭代对象前面时,有一个特殊的用途,称为“解包”(unpacking)。当你将一个可迭代对象放在星号 *
后面时,它会在那个位置展开成多个元素。
ans = [yi, *wan, qian, bai, shi, ge]
假设 wan
是一个列表(或者任何可迭代对象),那么 *wan
会将 wan
列表中的所有元素解包并插入到 ans
列表的相应位置。这样做的好处是你可以很容易地将一个列表的内容插入到另一个列表的特定位置,而不需要逐个元素地添加。
例如,如果 wan
是 [1, 2, 3]
,那么:
ans = [yi, *wan, qian, bai, shi, ge]
等价于:
ans = [yi, 1, 2, 3, qian, bai, shi, ge]
如果没有使用 *
运算符,而只是写了 wan
,那么 wan
本身(作为一个整体列表)会成为 ans
列表的一个元素,而不是它的内容被解包成多个元素。
例如:
# 假设 wan = [1, 2, 3]
ans = [yi, wan, qian, bai, shi, ge]
这将导致 ans
变为:
[yi, [1, 2, 3], qian, bai, shi, ge]
这不是我们想要的结果,因为通常我们希望将 wan
列表的内容与其他元素合并成一个单一的列表,而不是将 wan
作为一个子列表包含在内。因此,使用 *
运算符是处理这种情况的正确方法。
以下为本题完整AC代码:
# 定义一个字典,存储数字0-9的中文大写形式
mp = {}
for i in range(10):
mp[i] = ['ling', 'yi', 'er', 'san', 'si', 'wu', 'liu', 'qi', 'ba', 'jiu'][i]
n = input()
# 特判一下0的这种情况
if n == '0':
print(mp[int(n)])
exit(0)
# 如果输入包含负号,则在结果前添加'Fu ',并去掉负号
fu = ''
if '-' in n:
fu = 'Fu'
n = n[1:]
# 将输入的数字字符串前填充0至长度为9,便于后续处理
n = n.zfill(9)
# 提取亿位
high = int(str(n[0]))
high = mp[high] + ' Yi' if high else '' # 如果亿位为0,则置为空串
# 提取千万位、百万位、十万位、万位(注意这里的变量名q, b, s, g不代表这些位数)
mid = n[1:5]
q, b, s, w = map(int, mid)
# 将这些位数转换为中文大写形式,如果为0则转换为'ling'
q = mp[q] + ' Qian' if q else 'ling'
b = mp[b] + ' Bai' if b else 'ling'
s = mp[s] + ' Shi' if s else 'ling'
w = mp[w] if w else 'ling'
# 将万位及以上的部分存入列表wan
mid = [q, b, s, w]
while mid and mid[-1] == 'ling':
mid.pop() # 去除末尾'ling'
"""
work函数的作用:
将连续的多个'ling'变成一个'ling'
如li = ['ling','ling','er','san','ling','ling','ling','wu']则转换成['ling','er','san','ling','wu']
"""
def work(li):
# 初始化一个变量来存储前一个元素(None,如果还没有元素)
prev_element = None
result = []
for item in li:
# 如果当前元素不是'ling'或者它不是连续出现的'ling'
if item != 'ling' or (item == 'ling' and item != prev_element):
result.append(item)
# 更新前一个元素为当前元素
prev_element = item
return result
mid = work(mid)
"""
存在一种可能,亿位(high位为0),并且mid位前几位为0,这种情况要将mid前几位0去掉。如这样的数据:100800,在本代码中该数据首先被转换为0 0010 0800
应该读yi Shi Wan ling ba Bai,而不是ling yi Shi Wan ling ba Bai
"""
# 将mid前几位'ling'去掉,由于上面的work操作后,如果前几位有'ling',也只可能是一个'ling'
if high == '' and mid and mid[0] == 'ling':
mid.pop(0) # 去除开头'ling'
if mid and mid != ['ling']: # 判断连接mid和low是否需要添加'Wan'
mid.append('Wan')
else:
mid = []
# 提取千位及以下的具体数字(千位、百位、十位、个位)
qian = int(str(n[5]))
bai = int(str(n[6]))
shi = int(str(n[7]))
ge = int(str(n[-1]))
# 将千位及以下的具体数字转换为中文大写形式
qian = mp[qian] + ' Qian' if qian else 'ling'
bai = mp[bai] + ' Bai' if bai else 'ling'
shi = mp[shi] + ' Shi' if shi else 'ling'
ge = mp[ge] # 个位不需要添加单位
low = [qian, bai, shi, ge]
while low and low[-1] == 'ling':
low.pop() # 去除末尾'ling'
low = work(low)
"""
由于存在一种可能,亿位(high位为0),并且mid的4位全为0,这种情况要将low前几位0去掉:
只有当high为0,在代码中体现为空串,mid全为0,在代码中体现为[],这种情况才将low的前面的'ling'删掉,如80,在本代码中该数据首先被转换为0 0000 0080,应该读ba shi
当输入为800000008时,若下面的if语句前面不加上high == '',那么则输出ba Yi ba,这是不对的,正确答案是ba Yi ling ba
"""
# 将low前几位'ling'去掉,由于上面的work操作后,如果前几位有'ling',也只可能是一个'ling'
if high == '' and mid == [] and low and low[0] == 'ling':
low.pop(0) # 去除开头'ling'
# 将所有部分组合成一个列表ans
ans = [high, *mid, *low]
# 去除每个元素前后的空格,并将列表转换为字符串
ans = [i.strip() for i in ans]
ans = ' '.join(ans).strip()
# 如果输入是负数,则在结果前添加'Fu '
ans = f"{fu} {ans}".strip().split()
# 输出最终结果,去除可能由于添加'Fu '而产生的多余空格
print(' '.join(ans))