Python实例分析(二)删除“字典”中的释义内容
书接上回,我们完成了删除空行之后,下一步就是将释义内容删掉。大体思路是:
每行从左起,找到第一组拼音,然后找到这组拼音的最后一个字符,截取这个字符(含)之前的内容,写入目标文件。
这个思路主要来源于源文件的结构形式,当然在实际操作中还遇到了一些困难,我们边讲边说。
判断拼音
看了实例分析(一),想必大家都知道怎么读取源文件了。那就简单列一下:
>>> f=open('/Users/gaoqy/Desktop/source.txt','r')
>>> w=open('/Users/gaoqy/Desktop/target.txt','w')
>>> data=f.readlines()
以上就是我读取的文本内容。同样我也是截取一部分做测试和演示,这个与(一)中的内容不同,因为涉及到几个问题,需要。
因为我们会用到for循环遍历每行内容,首先我们先把循环体内部的逻辑、代码弄清楚。所以,我们用line先取data列表中的一行,做测试:
>>> line = data[0]
>>> line
'【阿Q】ĀQ名鲁迅小说《阿Q正传》的主人公,是“精神胜利者”的典型,受了屈辱,不敢正视,反而用自我安慰的办法,说自己是“胜利者”。\n'
line = data[0],是将data列表中的第一个元素赋值给line。第一个元素的序号是0,第二个元素的序号是1,依次类推。
然后我们检验一下,确认line的值为data中的一个元素。以下操作,我们就针对line测试即可。
要判断拼音,我们需要先做一个拼音的集合,为什么此时是集合呢?因为集合与列表的最主要区别就是,集合中的元素是无序的、唯一的。我们的拼音只需要集合就可以了。
>>> pinyin = set('aoeiuüāōēīūǖáóéíúǘǎǒěǐǔǚàòèìùǜAOEIUÜĀŌĒĪŪǕÁÓÉÍÚǗǍǑĚǏǓǙÀÒÈÌÙǛ•∥’bpmfdtnlgɡkhjqxzcsrwyWYBPMFDTNLGKHJQXZCSRH')
这是我自己做的pinyin集合,包括了在源文件中,拼音位置出现的所有字符,包括带不同声调的韵母,还有带两个点的ü以及间隔符等等。这个集合只针对这个源文件而做,不确定有没有普适性。
做好了pinyin集合后,我们就可以用in和not in判断一个字符是否在这个集合中。先演练一下:
>>> '我' in pinyin
False
>>> '我' not in pinyin
True
>>> 'i' not in pinyin
False
>>> 'i' in pinyin
True
找到拼音的结尾
截取字符串,我们需要确定末位,也就是拼音的结尾。先用while循环确定拼音的起始位置,然后再用while循环确定拼音的结束位置。
那为什么先要判断拼音的起始位置?因为流程大概是这样的:
第一个字符是不是拼音字符? 哦,不是,下一个;
第二个字符是不是拼音字符?哦,不是,下一个;
第三个字符是不是拼音字符?哦,是,开始找结尾;
第四个字符是不是拼音字符?哦,是,下一个;
第五个字符是不是拼音字符?哦,是,下一个:
第六个字符是不是拼音字符?哦,不是,好了,就到这!
如果不先找到拼音的起始位置,那么第一字符不是拼音字符时,这个判断就已经结束了。(或许会有更好的逻辑,那另说,反正我就讲我的思路,就是这么傲娇♂️)
我们先换一个line值:
line = data[1]
>>> line
'【阿是穴】āshìxué名中医在针灸上把没有固定名称的穴位,以酸、麻、胀、痛等感觉最明显的部位或病痛处作为穴位,叫做阿是穴。\n'
从左往右确定拼音起始位置,这里我们用i来遍历~
>>> i = 0
>>> i
>>> while line[i] not in pinyin:
... i += 1
...
前三行,先确定i为0;while循环,当line的i号字符不为拼音字符的时候,i增加1,然后循环判断,直至line的i号字符为拼音字符时停止。
>>> i = 0
>>> i
>>> while line[i] not in pinyin:
... i += 1
...
>>> i
5
>>> line[i]
'ā'
可以看到,当循环结束时,i值为5,line[i]为'ā'。line[i]确实是我们要找的“阿是穴”拼音的起始位置。
然后我们再来确定结束位置:
>>> while line[i] in pinyin:
... i += 1
...
>>> i
12
>>> line[i]
'名'
此时我们不需要初始化i的值,直接接着判断line[i]是否为拼音字符,如果是,i增加1,然后循环判断,直至line[i]不是拼音字符。
可以看到i值为12的时候,line[i]为'名',是拼音之后的第一个字符。
>>> print(line[:i])
【阿是穴】āshìxué
>>> print(line[0:i])
【阿是穴】āshìxué
找到拼音结束位置,我们就可以截取字符串了,(字符串也可以理解为一个列表)直接用字符串参数即可。这里需要注意的是,参数正常是[x:y],x是起始序号,y是数量,指的是,从第x号开始的y个元素。因为序号是从0而不是1开始,所以[0:i]刚好是指到拼音结束。
遇到问题 一
为啥刚刚在傲娇之后要换一个line值?当然,并不是我欠欠的~。我们用上述方法处理“阿Q”的词条,就发现了一个问题,词条中就出现了拼音字符!
>>> line = data[0]
>>> line
'【阿Q】ĀQ名鲁迅小说《阿Q正传》的主人公,是“精神胜利者”的典型,受了屈辱,不敢正视,反而用自我安慰的办法,说自己是“胜利者”。\n'
>>> i = 0
>>> while line[i] not in pinyin:
... i += 1
...
>>> while line[i] in pinyin:
... i += 1
...
>>> print(line[:i])
【阿Q
第一二行,我们把line的值换回成data[0],然后通过我们之前的解决方法操作,最后得到的结果是“【阿Q”,还没进入真•拼音部分,就结束了,因为词条中出现了Q,Q也是我们pinyin集合里的元素。
解决思路
用“先找到拼音起始位置”同样的思路,我们先找到词条的结尾(也就是“】”)然后再开始找拼音的起始位置……
>>> i = 0
>>> while line[i] != '】':
... i += 1
...
>>> i
3
>>> line[i]
'】'
用while循环找到'】',此时再用我们之前方法即可找到拼音的结束位置。
>>> i
3
>>> line[i]
'】'
>>> while line[i] not in pinyin:
... i += 1
...
>>> while line[i] in pinyin:
... i += 1
...
>>> print(line[:i])
【阿Q】ĀQ
注:这里的ĀQ并不是拼音,而是一个拼音加一个英文字母。鉴于这是个案,我们先不考虑这种问题的具体解决方法,只提供思路:找到【】中的英文字母,然后再找到拼音,从拼音中删掉找到的字母,这样就可以了,不过过于麻烦,这里不讲了,有兴趣可以自己试试,然后我们私下探讨。
写成py文件
套上一个遍历data列表的for循环,我们可以将上述代码写成py文件:
写完之后,兴高采烈地跑了一下source文件,结果报错了~
我们刚才的思路没问题,也是经过检验的。然后我又查看了一下报错内容,和目标文件,才发现了问题的根源。
遇到问题 二
我们看一下报错内容,第九行代码,i的值超出范围了;然后我又看了一下目标文件,正确地输出了3行:
所以,问题可能出现在源文件的第四行内容上。一定是不符合我们假设的格式。果然不出所料,第四行是个“另见1563页yān。”(如下图),这不符合我们代码所处理的格式,所以i没有遇到“】”就不停的累加,最后到写入的时候,超出了line[:i]的正确值,所以报错了。
注:这里的文档是演示用的,其实一眼就能看到这个问题,所以可以在写代码之前就做好准备,然而我在做的时候,只是大致扫了一下文档(足足8mb大小),没有注意到,因此犯了错。
解决思路
再仔细分析一下文档的结构,我们的需要的内容都是以“【”开始的,那么我们先进行一个判断,行首为“【”时,处理这行内容;行首不为“【”时,不处理这行内容,跳过即可。
所以在while循环前,加一个if条件判断:
>>> if line[0] == '【':
... print(line)
...
其实,肯定是没有问题的,不过还是来测试一下:
先用出错的那行,data[3],没有返回;再用没出错的任意一行,如data[1],返回了该行内容。说明判断起作用了,我们把它加到代码中:
第9行是新加的,10至17行需要嵌套进if判断中,所以要多加一个缩进,别忘了。
使用效果
源文件
处理后
当然具体实践过程中还遇到了很多奇葩的问题,比如编码不统一、源文件处理不规范、“g”和“ɡ”不是一个东西等等……词条后的括号内容,我也没删,担心老板会有参考之用。
其实是我懒诶
停!停!停!!
“g”和“ɡ”不是一个东西?!
️️️
对,它俩不是一个东西,有图为证:
我搜索了英文字母“g”,然而图中拼音里的“ɡ”并没有检索到(未标注),如果是同一个字符,应该如下图那样,所以这两个应该是外表极其相似的不同字符。最后都统一到英文的g了(因为输入方便)。
总之,解决了种种疑难杂症之后,才完成任务。所以写完程序后一定要检查,一定要细心。
领取专属 10元无门槛券
私享最新 技术干货