最近作业要做文本压缩,要用到不少相关的代码,刚好自己这一块不怎么熟,可能以后也会用到,所以总结一番。
读取文件
python
with open(file_path, 'r', encoding='utf-8') as f:
text = f.read()
这意味着:以只读模式 r 打开这个路径对应的文件,按照 UTF-8 编码解码成 Python 字符串。
一般会加with:with ... as f::用上下文管理器保证用完会自动关文件。
如果我们不选择with ... as,当然也有以下的等价写法,但是就会需要手动关闭,否则文件会一直占用内存。
python
f = open(file_path, 'r', encoding='utf-8')
text = f.read()
f.close()
去除所有空白字符
python
visible_chars = [ch for ch in text if not ch.isspace()]
ch.isspace()就是检测这个字符是不是换行,空格等等
Python中创建字典以统计字母数量
python
freq = {}
for ch in visible_chars:
freq[ch] = freq.get(ch, 0) + 1
在python中不需要像C++那样使用std::map<char, int> 来创建字典,只需要:freq = {},就会默认创建新的空字典。
类比来说:
[]是创建新列表,类似于C++的std:vector()是创建新元组,对应的是C++的std::tuple
在这里,实际上还有一个逻辑需要留意,在C++中,我们如果创建一个map,并且指定某个key,如果该key不存在,C++会自动创建一个新的key。
例如
cpp
freq['a']++;
如果'a'不存在,C++会自动创建一个新的key,且设置默认值为0。
这一点与python的dict不同,python如果面对不存在的key,会抛出keyerror。
bash
freq[ch]+=1
KeyError: '\ufeff'
因此一般会用:
python
freq[ch] = freq.get(ch, 0) + 1 #dict.get(key, default)
来面对这种情况,后面的数字为默认值,实际上就是类似于打印C++里的freq['c']。
读取编码表
试想我们已经得到了一个symbol和code的对应表格,我们怎么样逐行字符处理获得symbol和code呢?
例如这个txt可能如下:
bash
0: 1100000110111110
1: 110000011010001
2: 1100000110110001
3: 11000001101111010
我们可以用比较优雅的方式读取:
python
for line in f:
if ':' not in line:
continue
sym, code = line.strip().split(':')
这里的line.strip()是必要的,因为他会把读取字符串两侧的制表符,空格和换行符都删除。
python的line in f实际上是不断调用readline() 会一直读取字符,直到遇到 \n(换行符)或文件末尾 EOF;然后返回包含那一整行的字符串(包括末尾的 \n)。
sym, code = line.strip().split(':')是一个序列解包 过程,它自动将列表的第一个元素赋给sym,第二个元素赋给 code。实际上这样不稳健,如果我们的encode代码会写入两个冒号就会使得报错(因为此时每一行被分为了大于两份)。
我们可以使用sym, code = line.strip().split(':', 1) 来只按照第一个冒号区分。
python中读取系统参数列表
假设我们需求在运行脚本时就同时传入,码字对应表,编码文件和输出文件。例如:
bash
python XXX.py <code-file-path> <source-file-path> <output-file-path>
Python 会自动把命令行里的这些"空格分开的字符串"放进 sys.argv,一般我们不需要程序名字本身,所以会用sys.argv[1:]来读取后面的几个。根据数量我们就可以提前抛出错误了。
python
if len(sys.argv) != 5:
print("You should enter format like: python XXX.py <method> <op> <input> <output>")
sys.exit(1)
对源文件进行Encode
python
bits = ''
for ch in text:
if ch in code_map:
bits += code_map[ch]
简约的字典赋值版本为:
python
bits = ''.join(code_map[ch] for ch in text if ch in code_map)
可以理解为:
-
逐个取出原文中的字符 ch
-
查找 code_map[ch] 得到对应的二进制编码
-
把这些二进制字符串拼接起来