【字符串操作与应用】广东药科大学实验指导(实验5-字符串操作与应用)

实验5 - 字符串操作与应用

    • 基础认识填空
    • 程序编写
      • 一、数字金字塔
        • 确认问题
        • 分析问题
        • 代码实现
      • 二、九九乘法表
        • 确认问题
        • 分析问题
        • 代码实现
      • 三、同构数
        • 确认问题
        • 分析问题
        • 代码实现
          • 难点
      • 四、文本加密
        • 确认问题
        • 分析问题
        • 代码实现
      • 五、字母对称塔
        • 确认问题
        • 分析问题
        • 代码实现
    • 写在最后

基础认识填空

按照顺序依次输入以下语句,观察并记录IDLE的输出,领会其执行效果。

序号 输入语句 输出 功能说明
1 >>> a=“1234567890”
2 >>> print(a[0],a[8]) 1 9
3 >>> print(a[-1],a[-8]) 0 3
4 >>> print(a[2:7],a[1:8:2]) 34567 2468
5 >>> print(a[2:-2],a[-1:1:-1]) 345678 09876543
6 >>> print(a[:6],a[2:]) 123456 34567890
7 >>> print(a[::-1]) 0987654321
8 >>> print(a[::2]) 13579

这一题比较简单,这里小编就跳过了,大家就自行领会吧.

程序编写

程序编写环境:Windows11、PyCharm 2022.2.3 (Professional Edition)

Python解释器版本:Python 3.11.0(老早就想用python311了,但是因为刚出的时候没有python的工程项目,就一直闲置了下来)

一、数字金字塔

要求:输入正整数n,输出以下数字金字塔前n行(n<10)。

确认问题

我们需要用代码实现如下的金字塔,该示例金字塔为七层

      1
     222
    33333
   4444444
  555555555
 66666666666
7777777777777

分析问题

  1. 首先,我们需要从键盘输入一个整数来确定金字塔的层数

  2. 其次,我们要通过金字塔的层数计算出金字塔每层的空格并观察它的规律

  3. 然后,我们需要通过观察每层数字的个数与层数的关系找出其中的规律

代码实现

第一步:定义一个变量存储键盘录入的数

zs = int(input("请输入要打印的金字塔的层数:\n"))  # 定义一个变量存储正整数,并将 zs 从字符串型(str) 转换为整形(int)

第二步:计算金字塔每层的空格并观察出规律

设一共有 n 层,那么第 i 层的空格数就是 n - i 个。

" " * (n - i)	# 第 i 层的空格数

第三步:观察每层数字的个数并找出其与层数的关系

设有 n 层,那么第 i 层数字的个数就是 2 * i - 1 个,并且打印的数字与层数相同

2 * i - 1	# 第 i 层的数字的个数

第四步:异常处理

因为输入的过程中,可能会遇上一些不同的情况,比如:输入的时候不小心输入了一个特殊字符或者字母等的情况,此时程序就会产生异常,如果这种异常抛给 main() 方法,最终就会终止我们的程序,这并不是我们在应用中想见到的情况,所以为了解决这个问题,我们还需要进行异常处理。

在这题,我们可能会遇上的异常有两种,第一种是数值类型异常,第二种是数值范围异常。

  1. 数值类型异常

    可以用 python 内置的 ValueError() 方法进行异常处理,具体方法重写如下:

    try:
        pass  # 这部分写要执行的方法体,假设此方法体出现数值类型异常,那么就会进入下面 except
    
    except ValueError:  # 如果 zs 不是整数字符串,触发数值类型异常
        print("输入的数据非整数类型,请重新输入!\n")
    
  2. 数值范围异常

    因为没有内置的方法,所以我们决定自定义一个异常类,具体如下:

    class MSizeError(Exception):  # 定义一个自定义异常处理
        def __init__(self):
            self.str = "输入的数值超出范围,请重新输入\n"
        
        def __str__(self):
            return self.str
        
    try:
    	if not 0 < zs < 10:  # 检查是否为整数字符串并且是否小于 10
            raise MSizeError()  # 抛出异常
    except MSizeError as e:  # 触发数值范围异常
        print(e)
    

最终代码:

# 数字金字塔,输入正整数n,输出以下数字金字塔前n行(n<10)。

class MSizeError(Exception):  # 定义一个自定义异常处理
    def __init__(self):
        self.str = "输入的数值超出范围,请重新输入\n"
    
    def __str__(self):
        return self.str


if __name__ == '__main__':
    while True:
        try:
            zs = int(input("请输入要打印的金字塔的层数:\n"))  # 定义一个变量存储正整数,并将 zs 从字符串型(str) 转换为整形(int)
            if not 0 < zs < 10:  # 检查是否为整数字符串并且是否小于 10
                raise MSizeError()  # 抛出异常
            break  # 若无异常则结束循环
        except ValueError:  # 如果 zs 不是整数字符串,触发数值类型异常
            print("input is not digit!\n")  # 输出提示:所输入的并不是整数字符串
        except MSizeError as e:  # 如果 zs ≥ 10,触发数值范围异常
            print(e)
    
    for i in range(1, zs + 1):  # for循环打印 zs 层金字塔
        print(" " * (zs - i) + f"{i}" * (2 * i - 1))  # 打印第 i 层金字塔的数字和空格

拓展:

如果我们不用异常处理,我们还可以用 isdigit() 的方法去检查字符串是否为整数字符串
str.isdigit()	# isdigit() 是一个用于检查 str 字符串是否为整数字符串的函数

f"{i}"	# 这里的 f 是 format() 的一种用法,用于字符串中,{} 里面的是变量名	

二、九九乘法表

要求:

从键盘输入k(k<10),输出九九乘法表的前k行的结果,效果如下(每项乘积式占8列宽度,左对齐)。

确认问题

我们需要用代码实现如下的乘法表,该示例乘法表为前七行

1*1=1   1*2=2   1*3=3   1*4=4   1*5=5   1*6=6   1*7=7   
        2*2=4   2*3=6   2*4=8   2*5=10  2*6=12  2*7=14  
                3*3=9   3*4=12  3*5=15  3*6=18  3*7=21  
                        4*4=16  4*5=20  4*6=24  4*7=28  
                                5*5=25  5*6=30  5*7=35  
                                        6*6=36  6*7=42  
                                                7*7=49

分析问题

  1. 首先,我们需要从键盘录入一个整数 n 来确定我们要打印乘法表的前 n 行
  2. 其次,我们需要观察乘法表中的算术表达式并找出规律
  3. 然后,我们需要观察每一乘法表达式表达所占的列数,总结出规律,题目给出的是每个乘法表达式单元8列

代码实现

第一步:从键盘录入一个整数

zc = int(input("请输入需要打印的乘法表的总行数:\n"))  # 从键盘录入一个整数

第二步:观察乘法表中的算术表达式并找出规律

若把每一个乘法表达式看做一个单元,那么第 x 行、第 y 列单元、乘积为 z 的乘法表达式为:
x ∗ y = z x * y = z xy=z

第三步:实现占位

若把每一个乘法表达式看做一个单元,那么每一个单元所占的位置为8列,而空格的个数会因为乘积的不确定而显不确定性,也就是说,我们能确定的是乘法表达式占位大约为 5~6 列,剩下的由空格进行占位。那么我们就可以用到一个字符串的函数

str.ljust(8, " ")	# 字符串 + 空格一共占 8 列位置

第四步:异常处理

因为输入的过程中,可能会遇上一些不同的情况,比如:输入的时候不小心输入了一个特殊字符或者字母等的情况,此时程序就会产生异常,如果这种异常抛给 main() 方法,最终就会终止我们的程序,这并不是我们在应用中想见到的情况,所以为了解决这个问题,我们还需要进行异常处理。

在这题,我们可能会遇上的异常有两种,第一种是数值类型异常,第二种是数值范围异常。

  1. 数值类型异常

    可以用 python 内置的 ValueError() 方法进行异常处理,具体方法重写如下:

    try:
        pass  # 这部分写要执行的方法体,假设此方法体出现数值类型异常,那么就会进入下面 except
    
    except ValueError:  # 触发数值类型异常
        print("输入的数据非整数类型,请重新输入!\n")
    
  2. 数值范围异常

    因为没有内置的方法,所以我们决定自定义一个异常类,具体如下:

    class MSizeError(Exception):  # 定义一个自定义异常处理
        def __init__(self):
            self.str = "输入的数值超出范围,请重新输入\n"
        
        def __str__(self):
            return self.str
        
    try:
    	if not 0 < zc < 9:  # 如果输入的数据不在 1~9 之间,则触发异常,因为我们做的是九九乘法表
            raise MSizeError()  # 抛出异常
    except MSizeError as e:  # 触发数值范围异常
        print(e)
    

最终代码:

# 从键盘输入k(k<10),输出九九乘法表的前k行的结果

class MSizeError(Exception):  # 定义一个自定义异常处理
    def __init__(self):
        self.str = "输入的数值超出范围,请重新输入\n"
    
    def __str__(self):
        return self.str


if __name__ == '__main__':
    while True:
        try:
            zc = int(input("请输入需要打印的乘法表的总行数:\n"))  # 从键盘录入一个整数,并转换为整形
            if not 0 < zc < 9:  # 如果输入的数据不在 1~9 之间,则触发异常,因为我们做的是九九乘法表
                raise MSizeError()  # 抛出异常
            break  # 若无异常则结束循环
        except ValueError:  # 触发数值类型异常
            print("输入的数据非整数类型,请重新输入!\n")
        except MSizeError as e:  # 触发数值范围异常
            print(e)
    
    for i in range(1, zc + 1):  # 用 i 记录乘法表第几层
        for j in range(1, zc + 1):  # 这个 for 循环单纯记录 j 的值
            if j < i:  # 如果 j < i ,即该行前 i 个单元不需要打印乘法表
                print("".ljust(8), end="")  # 打印八个空格,因为此时不需要打印乘法表的数据;结尾不换行,直到该行的所有表达式单元输出完毕
                continue  # 结束此次循环,并进入下一次循环
            out = f"{i}*{j}={i * j}"  # 用变量 out 来记录每个乘法表达式
            print(out.ljust(8), end="")  # 打印每个乘法表达式单元,结尾不换行,直到该行的所有表达式单元输出完毕
        print()  # 换行

拓展:

str.ljust(x, y)	# ljust() 是一个字符串的函数,其中 x 为 str 字符串所占列的总数,y 参数是当 str 字符串所占的列数不足 x 列时用 y 来进行占位,默认为空格

三、同构数

要求:输入整数n(n<10),求前n个同构数

因为受到前几题的影响,在小的看来,如果只求 n<10 好像有点将程序写死的感觉,所以鄙人仔细想了点别的办法,避免了这个问题,各位客官请接着往下瞧

同构数的概念:
一整数若正好为其平方数的尾部,则称该数为同构数

例如,5正好是25的尾部,故5为同构数)

确认问题

我们需要使用代码打印如下的输出语句,示例为输出6个同构数

NO1:5
NO2:6
NO3:25
NO4:76
NO5:376
NO6:625

分析问题

  1. 首先,我们需要从键盘录入一个整数来确定我们需要输出多少个同构数
  2. 其次,我们需要分析示例输出的共同点和不同点
  3. 最后,我们需要分析同构数的共同点和特殊点

代码实现

第一步:从键盘录入一个整数

zc = int(input("请输入需要查询的同构数的数量:\n"))  # 从键盘录入一个整数

第二步:分析示例输出的共同点和不同点

  1. 共同点:

    NO1:
    NO2:
    NO3:
    NO4:
    NO5:
    NO6:
    

    在第 i 行打印输出为 (NO + i +

  2. 不同点:

    NO1:5
    NO2:6
    NO3:25
    NO4:76
    NO5:376
    NO6:625
    

    每一列的数据的同构数没有既定规律,也就是说我们需要根据数据来想想别的办法探寻规律

第三步:分析同构数的共同点和特殊点

  1. 共同点:

    每个同构数都是它自己平方的尾数,举个栗子:
    假设同构数为 5,则平方后为 25,尾数就是 5
    假设同构数为 25,平方后为 625,尾数就是 25
    
  2. 特殊点:

    同构数的位数决定了平方后尾数的尾数,举个栗子:
    假设同构数为 5,则平方后为 25,那么尾数就是一位,就是 5
    假设同构数为 25,平方后为 625,那么尾数就是两位,就是 25,以此类推 
    
    这里有个要注意的点,因为 01 的平方都是它们自己,所以我们循环的时候需要注意跳过 01,直接从 2 开始
    

因为输入的过程中,可能会遇上一些不同的情况,比如:输入的时候不小心输入了一个特殊字符或者字母等的情况,此时程序就会产生异常,如果这种异常抛给 main() 方法,最终就会终止我们的程序,这并不是我们在应用中想见到的情况,所以为了解决这个问题,我们还需要进行异常处理。

  1. 数值类型异常

    可以用 python 内置的 ValueError() 方法进行异常处理,具体方法重写如下:

    try:
        pass  # 这部分写要执行的方法体,假设此方法体出现数值类型异常,那么就会进入下面 except
    
    except ValueError:  # 如果 zs 不是整数字符串,触发数值类型异常
        print("输入的数据非整数类型,请重新输入!\n")
    
难点
  1. 打印同构数数量的不确定性

    由于需要打印同构数数目的的不确定性,也需要找一个表示无穷大的数来防止数据的溢出,那么此时就需要用到 python 的内置库函数 sys

    import sys  # 导入 sys 模块
    
    以下是 sys 模块的所包含的所有对象的名称:
    
    ['__displayhook__', '__doc__', '__excepthook__', '__loader__', '__name__',
     '__package__', '__stderr__', '__stdin__', '__stdout__',
     '_clear_type_cache', '_current_frames', '_debugmallocstats', '_getframe',
     '_home', '_mercurial', '_xoptions', 'abiflags', 'api_version', 'argv',
     'base_exec_prefix', 'base_prefix', 'builtin_module_names', 'byteorder',
     'call_tracing', 'callstats', 'copyright', 'displayhook',
     'dont_write_bytecode', 'exc_info', 'excepthook', 'exec_prefix',
     'executable', 'exit', 'flags', 'float_info', 'float_repr_style',
     'getcheckinterval', 'getdefaultencoding', 'getdlopenflags',
     'getfilesystemencoding', 'getobjects', 'getprofile', 'getrecursionlimit',
     'getrefcount', 'getsizeof', 'getswitchinterval', 'gettotalrefcount',
     'gettrace', 'hash_info', 'hexversion', 'implementation', 'int_info',
     'intern', 'maxsize', 'maxunicode', 'meta_path', 'modules', 'path',
     'path_hooks', 'path_importer_cache', 'platform', 'prefix', 'ps1',
     'setcheckinterval', 'setdlopenflags', 'setprofile', 'setrecursionlimit',
     'setswitchinterval', 'settrace', 'stderr', 'stdin', 'stdout',
     'thread_info', 'version', 'version_info', 'warnoptions']
    
    在这题,我们需要使用其中的 maxsize 对象,maxsize 表示无穷大
    

    拓展

    我们可以用内置的函数 dir() 可以找到模块内定义的所有名称。以一个字符串列表的形式返回

    使用方法:
    dir(模块名)
    
    如果没有给定参数,那么 dir() 函数会罗列出当前定义的所有名称:
    
    [in]: dir()
    [out]: ['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']
    
  2. 同构数尾数的不确定性

    因为我们并不知道同构数究竟是几位的数字,所以我们必须要定义一个变量来记录同构数的位数

    我们假设同构数为 x,那我们可以不断地让 x/10 直到 x 为零,然后我们用 count 来记录 x/10 运行的次数便可以算出同构数的位数
    
    count = 0  # 定义用来记录同构数的位数的对象 count,并赋值为 0
    while x:  # 用 while 循环来实现我们除法运算的操作,当 x 为 0 时,while 循环判断为假,即此时会跳出循环
        x = int(x / 10)  # 此时注意必须保证 x 是一个整形,否则将进入无限月读(循环)
        count = count + 1  # 记录循环语句执行的次数
    

最终代码:

# 输入整数n(n<10),求前n个同构数(一整数若正好为其平方数的尾部,则称该数为同构数

import sys

if __name__ == '__main__':
    while True:
        try:
            zc = int(input("请输入需要查询的同构数的数量:\n"))  # 从键盘录入一个整数
            break
        except ValueError:  # 触发数值类型异常
            print("输入的数据非整数类型,请重新输入!\n")
    
    a = []  # 定义一个列表 a,用于存储同构数
    for j in range(2, sys.maxsize):  # 因为我们并不确定同构数的平方到底多大,所以循环的终止我们使用无穷大表示
        count = 0  # 定义一个对象 count 来记录同构数的位数
        n = j  # 因为我们下面必须用同构数与同构数平方的尾数进行比较,所以这里插入一个临时变量 n 来记录同构数的大小
        while n:  # 用 while 循环来实现我们除法运算的操作,当 n 为 0 时,while 循环判断为假,即此时会跳出循环
            n = int(n / 10)  # 此时注意必须保证 n 是一个整形,否则将进入无限月读(循环)
            count += 1  # 记录循环语句执行的次数,这里可以参照上面那样写,写 += 也是没错的
        if len(a) == zc:  # 判断列表的长度是否已经满足需要输出的同构数数量,如果够了就不需要再往里面添加数据了,可以直接打印输出了
            break  # 结束当前循环
        elif j == (j ** 2 % (10 ** count)):  # 判断 j 是否为同构数
            a.append(j)  # 将同构数 j 的值添加入数组中
            continue  # 结束此次循环,进入下一次循环
    for i in range(zc):  # 这里循环用 i 记录一下打印第几个数
        print(f"NO{i + 1}:{a[i]}")  # 循环打印数组元素

冷知识:

sys.maxsize 中的定义为:
maxsize = 9223372036854775807
这是一个十进制数,将其转换为二进制之后为: 0111111111111111111111111111111111111111111111111111111111111111,其中 0 为符号位,表示正数,这就是计算机中整数类型的最大值(未溢出)
官方文档对 sys.maxsize 的解释:一个整数,表示 Py_ssize_t 类型的变量可以取到的最大值。在 32 位平台上通常为 2**31 - 1,在 64 位平台上通常为 2**63 - 1。

除了 sys.maxsize ,python中还有 sys.maxunicode ,因为没有用到,所以大家就看看官方解释就好了
官方文档对 sys.maxunicode 的解释:

一个整数,表示最大的 Unicode 码点值,如 1114111 (十六进制为 0x10FFFF )。
在 3.3 版更改: 在 PEP 393 之前,sys.maxunicode 曾是 0xFFFF0x10FFFF,具体取决于配置选项,该选项指定将 Unicode 字符存储为 UCS-2 还是 UCS-4

四、文本加密

要求:

输入一行字符,试按照以下加密规则对其加密后输出其密文形式

加密规则:
字母
	A-Z,B-Y,C-X...
	a-z,b-y,c-x...
数字
	0-9,1-8,2-7...
其他字符保持不变

确认问题

我们需要实现的是如下方的示例:

加密前:
	123,Up,I Love you China!
加密后:
	876,Fk,R Olev blf Xsrmz!

分析问题

  1. 从键盘录入一串字符串
  2. 将字符串中的每个字符分割开,并保留特殊字符和空格
  3. 对每个字符进行加密
  4. 将所有加密的字符重新组合形成一串新的字符串
  5. 打印输出加密后的字符串

代码实现

第一步:从键盘录入一串字符串

zfc = input("请输入需要加密的字符串:\n")  # 从键盘录入需要加密的字符串

第二步:将字符串中的每个字符分割开,并保留特殊字符和空格

将字符串分割的方式有很多种,可以切片,可以使用 python 的内置函数 split() 方法,但是这个方法需要有分隔符号,所以不太适合这道题

这里我选用的是 re 模块中的 split() 方法进行分隔,这个与 python 的内置函数不一样

因为这个方法返回的是个列表类型所以我是用了 python 的一个内置函数 filter() 方法,下面会分别拓展一下 re.split() 方法 和filter() 方法

pattern = r'[^a-zA-Z0-9]{0}'
szfc = filter(None, re.split(pattern=pattern, string=zfc, maxsplit=len(zfc)))

拓展:

  1. split()

    re.split(pattern, string, maxsplit=0, flags=0)
    
    re 模块中的 split() 方法有四个参数,分别是 pattern、string、maxsplit、 flags
    
    用 pattern 分开 string 。 如果在 pattern 中捕获到括号,那么所有的组里的文字也会包含在列表里。如果 maxsplit 非零, 最多进行 maxsplit 次分隔, 剩下的字符全部返回到列表的最后一个元素。
    

    举例:

    import re
    
    >>> re.split(r'\W+', 'Words, words, words.')
    ['Words', 'words', 'words', '']
    
    >>> re.split(r'(\W+)', 'Words, words, words.')
    ['Words', ', ', 'words', ', ', 'words', '.', '']
    
    >>> re.split(r'\W+', 'Words, words, words.', 1)
    ['Words', 'words, words.']
    
    >>> re.split('[a-f]+', '0a3B9', flags=re.IGNORECASE)
    ['0', '3', '9']
    
    
  2. filter()

    filter(function, iterable, /)
    
    用 iterable 中函数 function 返回真的那些元素,构建一个新的迭代器。iterable 可以是一个序列,一个支持迭代的容器,或一个迭代器。如果 function 是 None ,则会假设它是一个身份函数,即 iterable 中所有返回假的元素会被移除。
    
    请注意, filter(function, iterable) 相当于一个生成器表达式,当 function 不是 None 的时候为 (item for item in iterable if function(item));function 是 None 的时候为 (item for item in iterable if item) 。
    
    只有 function 返回 false 时才选取 iterable 中元素的补充函数。
    
    参数:
    function -- 判断函数。
    iterable -- 可迭代对象。
    

第三步:对每个字符进行加密

这里我选择使用列表存储 ASKII 码表的一些符号,以便我们的加密工作,我们需要用一个字典,以完成匹配工作,

特殊符号:

gg1 = [chr(i) for i in range(0, 48)]
gg2 = [chr(i) for i in range(58, 65)]
gg3 = [chr(i) for i in range(91, 97)]
gg4 = [chr(i) for i in range(123, 126)]

字典的键:

fo1 = [chr(i) for i in range(ord('A'), ord('Z') + 1)]
fo2 = [chr(i) for i in range(ord('a'), ord('z') + 1)]
fo3 = [str(i) for i in range(0, 10)]

fo = fo1 + fo2 + fo3 + gg1 + gg2 + gg3 + gg4

字典中的值:

en1 = [chr(i) for i in range(ord('Z'), ord('A') - 1, -1)]
en2 = [chr(i) for i in range(ord('z'), ord('a') - 1, -1)]
en3 = [str(i) for i in range(9, -1, -1)]

en = en1 + en2 + en3 + gg1 + gg2 + gg3 + gg4

最终字典:

jm = dict(zip(fo, en))  # 匹配字符所用的字典

第四步:将所有加密的字符重新组合形成一串新的字符串

jmzfc = ""  # 定义一个字符串对象,用于存储加密后的字符串
for i in szfc:
    jmzfc += jm.get(i)  # 遍历字符串匹配字符并加入到加密字符串

第五步:打印输出加密后的字符串

print(jmzfc)  # 打印输出加密后的字符串

最终代码:

# (3)	文本加密。输入一行字符,试按照以下加密规则对其加密后输出其密文形式(加密规则:字母A-Z,B-Y,C-X....a-z,b-y,c-x...,数字0-9,1-8,2-7...其他字符保持不变)。
import re

gg1 = [chr(i) for i in range(0, 48)]
gg2 = [chr(i) for i in range(58, 65)]
gg3 = [chr(i) for i in range(91, 97)]
gg4 = [chr(i) for i in range(123, 126)]

fo1 = [chr(i) for i in range(ord('A'), ord('Z') + 1)]
fo2 = [chr(i) for i in range(ord('a'), ord('z') + 1)]
fo3 = [str(i) for i in range(0, 10)]

fo = fo1 + fo2 + fo3 + gg1 + gg2 + gg3 + gg4

en1 = [chr(i) for i in range(ord('Z'), ord('A') - 1, -1)]
en2 = [chr(i) for i in range(ord('z'), ord('a') - 1, -1)]
en3 = [str(i) for i in range(9, -1, -1)]

en = en1 + en2 + en3 + gg1 + gg2 + gg3 + gg4

jm = dict(zip(fo, en))  # 匹配字符所用的字典

zfc = input("请输入需要加密的字符串:\n")  # 从键盘录入需要加密的字符串

pattern = r'[^a-zA-Z0-9]{0}'  # 匹配字符使用的正则表达式
szfc = filter(None, re.split(pattern=pattern, string=zfc, maxsplit=len(zfc)))  # 分割字符串,并且去除列表中的None元素,再返回字符串并赋值给 szfc 对象

jmzfc = ""  # 定义一个字符串对象,用于存储加密后的字符串
for i in szfc:
    jmzfc += jm.get(i)  # 遍历字符串匹配字符并加入到加密字符串
print(jmzfc)  # 打印输出加密后的字符串

拓展:

字典中,有三种查询方法是我们可以直接用的,比如 dict.key, dict.value, 最后就是我用的这一种,这个是通过 dict.get() 的方法进行查询,get里面的参数 key 在这里我们用的就是一个字符。

dict.get(key[, default])

如果 key 存在于字典中则返回 key 的值,否则返回 default。 如果 default 未给出则默认为 None,因而此方法绝不会引发 KeyError。

五、字母对称塔

要求:输入正整数s,显示字母金字塔的前s行

确认问题

我们需要实现的是如下方的示例金字塔:

    A
   ABA
  ABCBA
 ABCDCBA
ABCDEDCBA

分析问题

这题跟第一题的数字金字塔有一点点不太一样,所以我们还是要来分析一下

  1. 首先,我们需要从键盘输入一个整数来确定金字塔的层数
  2. 其次,我们要通过金字塔的层数计算出金字塔每层的空格并观察它的规律
  3. 然后,我们需要通过观察每层字母的顺序和个数与层数的关系找出其中的规律

代码实现

第一步:从键盘输入一个整数来确定金字塔的层数

zc = int(input("请输入需要打印的金字塔层数:\n"))  # 从键盘录入一个整数来确定打印多少层金字塔,并将数据转换为整数类型

第二步:通过金字塔的层数计算出金字塔每层的空格并观察它的规律

设一共有 n 层,那么第 i 层的空格数就是 n - i 个。

" " * (n - i)	# 第 i 层的空格数

第三步:观察每层数字的个数并找出其与层数的关系

设有 n 层,那么第 i 层字母的个数就是 2 * i - 1 个

2 * i - 1	# 第 i 层的字母的个数

但是因为字母是有正序和倒序,所以我们需要进行分类,分为正序和倒序

  1. 正序:

    设有 n 层,那么第 i 层正序的字母数与层数相等,例如:

    1 层:
    	A
    第 2 层:
       AB
    第 3 层:
      ABC
    
  2. 逆序:

    设有 n 层,那么第 i 层逆序序的字母数与为 i - 1,例如:

    1 层:
    	没有
    第 2 层:
         A
    第 3 层:
         BA
    

那么据此我们就可以将其分为两部分,正序和逆序打印:

fo = [chr(i) for i in range(ord('A'), ord('Z') + 1)]  # 正序将字母表添加进列表
en = [chr(i) for i in range(ord('Z'), ord('A') - 1, -1)]  # 逆序将字母表添加进列表

code1, code2 = "", ""  # 定义两个字符串对象,code1 和 code2
code1 = "".join(fo[:i])  # 将该层正序字母存入 code1
if i > 1:
    code2 = "".join(en[-i + 1:])  # 将该层逆序字母存入 code2

第四步:异常处理

因为输入的过程中,可能会遇上一些不同的情况,比如:输入的时候不小心输入了一个特殊字符或者字母等的情况,此时程序就会产生异常,如果这种异常抛给 main() 方法,最终就会终止我们的程序,这并不是我们在应用中想见到的情况,所以为了解决这个问题,我们还需要进行异常处理。

在这题,我们可能会遇上的异常有两种,第一种是数值类型异常,第二种是数值范围异常。

  1. 数值类型异常

    可以用 python 内置的 ValueError() 方法进行异常处理,具体方法重写如下:

    try:
        pass  # 这部分写要执行的方法体,假设此方法体出现数值类型异常,那么就会进入下面 except
    
    except ValueError:  # 触发数值类型异常
        print("输入的数据非整数类型,请重新输入!\n")
    
  2. 数值范围异常

    因为没有内置的方法,所以我们决定自定义一个异常类,具体如下:

    class MSizeError(Exception):  # 定义一个自定义异常处理
        def __init__(self):
            self.str = "输入的数值超出范围,请重新输入\n"
        
        def __str__(self):
            return self.str
        
    try:
    	if not 0 < zc < 9:  # 如果输入的数据不在 1~9 之间,则触发异常,因为我们做的是九九乘法表
            raise MSizeError()  # 抛出异常
    except MSizeError as e:  # 触发数值范围异常
        print(e)
    

最终代码:

# 输入正整数s,显示字母金字塔的前s行

class MSizeError(Exception):  # 定义一个自定义异常处理
    def __init__(self):
        self.str = "输入的数值超出范围,请重新输入\n"
    
    def __str__(self):
        return self.str


if __name__ == '__main__':
    fo = [chr(i) for i in range(ord('A'), ord('Z') + 1)]  # 正序将字母表添加进列表
    en = [chr(i) for i in range(ord('Z'), ord('A') - 1, -1)]  # 逆序将字母表添加进列表
    
    while True:
        try:
            zc = int(input("请输入需要打印的金字塔层数:\n"))  # 从键盘录入一个整数来确定打印多少层金字塔,并将数据转换为整数类型
            if not 0 < zc < 27:  # 如果输入的数据不在 1~26 之间,则触发异常,因为字母表只有26个字母
                raise MSizeError()  # 抛出异常
            break  # 若无异常则结束循环
        except ValueError:  # 触发数值类型异常
            print("输入的数据非整数类型,请重新输入!\n")
        except MSizeError as e:  # 触发数值范围异常
            print(e)
    
    code1, code2 = "", ""  # 定义两个字符串对象,code1 和 code2
    for i in range(1, zc + 1):  # 最外循环为打印行
        
        for j in range(zc - i):  # 打印空格
            print(' ', end='')
        
        code1 = "".join(fo[:i])  # 将该层正序字母存入 code1
        
        if i > 1:
            code2 = "".join(en[-i + 1:])  # 将该层逆序字母存入 code2
        
        print(code1 + code2)  # 打印字母金字塔

写在最后

上述就是这篇博客的全部内容,很感谢各位看官老爷能看到这里,在这里对各位老爷表以最诚挚的感谢;

这一篇博客写起来确实废了不少力气,本以为是一份很简单的题目,但是写着写着发现有点不对劲;因为本来写这份实验报告的时候,我去查找了一些资料,了解了一些字符串的用法,但是真正要去写进博客的时候我才发现,原来还有很多的不足;就比如写进去的一些冷知识和拓展,这些就是我以前从不会去了解的东西。当我认真去了解过才会发现,原来以前的我是真的太过于渺小了,总以为自己掌握了挺多东西了,但是真正遇上问题的时候,这些缺陷却全部都暴露出来了。

这次的博客我用上了一点点异常处理的知识,这本来是没打算写进博客中的,但是后面写到最后一份字母金字塔的时候,突然想到如果数字大于26该怎么办呢?然后因为我最近在学 JavaSE,刚好就学到异常处理这部分,又想起以前老师草草地提过一点点。之后我就花了几个小时去了解了一下异常处理这一块的知识(主要的时间还是花费在了自定义异常那边),然后写完了字母堆成塔才发现,刚好像乘法表和数字金字塔也可以用上异常处理,所以我又临时加上了这些内容。

在代码实现这一部分,我写了很多重复的异常处理部分,这并不是冗杂,因为我想大家不仅仅是看完这一篇博客能完成作业这种程度,我希望大家也能真正学到有关课堂老师可能没讲到的一些知识,这对大家的未来也是一件好事情。

这一篇虽然是实验五了,但是如果有空的话,我会给大家整理出之前漏掉的实验一到实验四。

最后还是很感谢大家能认真地看到这里,再次感谢各位看官老爷,祝各位万福金安!

你可能感兴趣的:(Python学习,python)