引言
你在编辑字典?在转换字典格式?从一本词典中筛选出四六级词汇,制作背单词软件词库?
在编辑器中,繁琐的查找替换工作、正则表达式不够用了,怎么办?每次重复的编辑操作是否可以保存起来以后直接使用?
其实你可以走得更远,本文即将使用python进行复杂的文本处理。(文科生不要灰心,我也是文科生)
python是一种脚本语言。脚本语言是什么?能干什么?
著名的脚本有javascript,它可实现诸多网页特效。还有PHP,论坛搭建一般都用它,以PHP结尾的网页就是。
近期的拙作pdbEditor、ZDicTool,都是用python写的。
准备
python,可以认为它是一个没有图形界面的编辑器。得给它一些命令语句让它执行。
逐条输入命令,它就会一条一条地执行;也可把多条命令存成一个后缀为“.py”的文件,然后一起执行。
所有#后面的文字都是注释,给人看帮助理解的,程序并不执行。
Linux中一般自带python,在Windows中,可下载安装。安装后,py 后缀的文件可直接双击执行。
运行开始菜单中的python\IDLE,可以看到“>>>”提示符,这里可以逐条输入执行命令。
在py文件中右键选择Edit with IDLE,或者使用ultraedit等编辑器,都可直接对py文件进行编辑。
简单查找替换
一段文字,可长可短,长到一个大文件,短到一个空字符串。可先用“=”把它们保存到一个变量中,方便多次查找、替换。
字符串也能像数字一样进行加法和乘法,是不是很直观?
word = 'I'
sep = ' /// '
mean = '我'
line = word + sep + mean # line的值就是 I /// 我
print line #在屏幕中输出以便查看line的值
print mean * 10 #会输出:我我我我我我我我我我
要进行查找替换,可以使用replace(查找内容,替换内容)函数。
如果不想全部替换,只想把前N个符合条件的给替换掉,则可以再加上第三个参数N表示查找替换次数。
line = line.replace(' /// ', '\t') #把line中的“ /// ”分隔符换成“\t”,仍然保存回line变量中,此时line值变为“I\t我”
new = 'aaa'.replace('a', 'A', 2) #把前两个小a换成大A,第三个不动。
要在一段文字里查找某个词,可以使用find函数,找到它在这个词中的位置(从0开始编号),若找不到则返回-1。
若要从后往前找,可以使用rfind函数。
a='abcda'
b='bcd'
pos1= a.find(b) #返回bcd所在的位置,为1
pos2 = a.find('a') #'a'在a中第一次出现的位置,为0
pos2 = a.rfind('a') #从后往前找,'a'在a中第一次出现的位置,为4
pos3 = a.find('e') #返回e所在的位置,找不到,为-1
知道了位置(又叫索引,从左往右依次是0、1、2),就可从一大段文字中挖掘有用的内容了。
line[0]#line中第0个字符。
ine[-1]#line中最后一个字符。索引还可以是负数,表示从右往左数,依次为-1、-2、-3等。
#要获得其中一部分字符,可以使用一个区间指定开始和结束位置,它包括开始索引字符,但不包括结束索引处的字符
line[0:10]#第0到9这十个字符,不包括第10个字符。
line[0:-1]#第0到-2这N-1个字符,不包括最后一个字符。
#当开始索引为0时,可以省略
line[:10]#也就是line[0:10]
line[:-1]#也就是line[0:-1]
#当要获得包括最后一个字符在内的一部分字符时,必须把结束索引省略
line[-10:]#获得最后十个字符
line[1:]#获得从1开始到最后的所有字符
help(str)可查询更多字符串操作。
高级查找替换:正则表达式
更复杂的查找、替换得求助于正则表达式(regular expression),在python中使用import re语句,就能用正则表达式了。
可以使用re.sub(正则表达式, 替换成字符, 源字符串)进行查找替换:
import re
s = re.sub('', '', s) #把s中所有之间的字符都替换成空字符,并保存回s
执行import re语句后,再执行help(re)可查询更多正则表达式操作。
读写文件
文件操作三步曲:打开、读取或写入、关闭。
要打开一个文件,并读取全部内容:
f=open('a.txt', 'r')#以读(r)的方式打开文件a.txt,保存到f变量,然后就可以通过f进行读取、关闭等操作。
content=f.read()#把文件内容全部读取到content变量中,要读取一行,可以使用readline函数
f.close()#关闭文件
要把content中的内容写入到文件b.txt中:
f=open('b.txt', 'w') #以写(w)的方式打开文件b.txt,保存到f变量,然后就可以通过f进行写入、关闭的操作。
f.write(content) #把content变量中的字符串全部写入到文件中,写完后不自动换行
f.close() #关闭文件
#或者
f=open('b.txt', 'w') #以写(w)的方式打开文件b.txt,保存到f变量,然后就可以通过f进行写入、关闭的操作。
print >>f, content #也可以使用print语句把字符串写入到文件中,写完后自动换行
f.close() #关闭文件
help(file)可查询更多文件操作。
排序、筛选、批处理
词典是按字母顺序排列的,那么怎样排序呢?光靠一个字符串就难以实现了,而列表可保存多个字符串,可以进行排序。
列表通常是使用[]表示的,可以使用sort函数对它进行排序。下面两句话就可以分别对a列表进行升序、降序排列。
a.sort()#正序
a.sort(reverse=True)#倒序
#如果不想改变原来的排列,可以使用sorted,获得排好序的新列表。
b = sorted(a) #a不变,把排好序的a保存到b中
b = sorted(a, reverse=True) #降序排列
但是,怎么样把这几段文字弄到列表里呢?
#可以直接建立
a=['bbb', 'ccc', 'aaa']
#也可先建一个空列表,然后通过append操作向其中逐步添加字符串。
a=[]#也可以使用a=list()建立一个空的列表
a.append('bbb')
a.append('ccc')
a.append('aaa')
#也可以通过文件中的readlines将所有的文件行读入到一个列表中
f=open('a.txt', 'r') #以读(r)的方式打开文件a.txt
a=f.readlines() #把文件内容全部读取到a变量中,每行为一个字符串(包括换行符\n)
f.close() #关闭文件
#还可以通过字符串的split函数,将一个分割成多个字符串,保存到列表中。
s = 'bbb\nccc\naaa' #字符串
a = s.split('\n') #以\n分隔字符串s,保存到a列表
也许并不是每个元素都有用,可以使用filter(判断函数,列表)筛选出所有使得判断函数的值为真的元素。
其中判断函数一般使用lambda函数,比如,要选出长度大于2的元素,函数可以写成:lambda x: len(x)>2
b = filter(lambda x: len(x)>2, a)#筛选出a中所有长度大于2的元素,并保存在b列表中
c = filter(lambda x: x[0]=='a', a)#筛选出a中以'a'开头的元素,并保存在c列表中
也许元素的值并不满足要求,可以使用map(处理函数,列表)对列表中每个元素进行处理。
b = map(str.upper, a) #把a中每个元素都变成大写,并保存在b中
b = map(lambda x:x[0], a) #把a中每个元素的第一个字符取出来,并保存在b中
b = map(lambda x:x[:x.find('\t')], a) #把a中每个元素\t前的所有字符取出来,并保存在b中
b = map(lambda x: x + '\n', a) #给每个元素末尾加个换行符,并保存在b中
怎么样把处理后的字符串列表保存到文件中去呢?
#若每个元素最后都有换行符\n,用readlines读出来的列表就是这样,它可以用writelines保存到文件中去。
f=open('b.txt', 'w') #以写(w)的方式打开文件b.txt
f.writelines(a) #把a列表中的所有字符串全部写入到文件中
f.close() #关闭文件
#若行末没有换行符,则可以先使用map给每个元素加上换行符,再使用writelines写入文件
f=open('b.txt', 'w') #以写(w)的方式打开文件b.txt
a = map(lambda x: x + '\n', a) #给每个元素末尾加个换行符
f.writelines(a) #把a列表中的所有字符串全部写入到文件中,
f.close() #关闭文件
#上述操作也许效率不高,可使用“\n”先将列表串联成一个大字符串,跟split的操作刚好相反
f=open('b.txt', 'w')#以写(w)的方式打开文件b.txt
s='\n'.join(a) #使用\n将a连接成一个字符串
f.write(s) #把字符串s写入到文件中
f.close() #关闭文件
#还可使用print写入文件,每次写入一个元素,存成一行,自动添加换行符
f=open('b.txt', 'w') # 以写(w)的方式打开文件b.txt
for element in a: #对a中每个元素进行处理,每次取出一个元素保存至element中
print >>f, element #每次写入一行,注意缩进,这句是for循环中的,比其他语句低一个层次
f.close() #关闭文件,这句在for循环外面,所以没有缩进
help(list)可查询更多列表操作。
比较文件、删除重复
文件经过多次编辑操作,可能会有重复的,列表就无能无力了,这时可以使用集合,因为集合中没有重复元素。
比如要把文件a.txt中的所有重复的行去掉,并按顺序输入到b.txt中
f=open('a.txt', 'r')
lines=f.readlines()#读取a中的所有行
f.close()
f=open('b.txt', 'w')
lines_set=set(lines) #使用set函数将所有行变成集合
lines=list(lines_set) #使用list函数将集合变成列表进行排序
lines.sort() #对lines进行升序排列
f.writelines(lines)
f.close()
#也许看起来很复杂,你可以使用下面的一句话实现所有过程
open('b.txt', 'w').writelines(sorted(set(open('a.txt', 'r').readlines())))
集合可以进行交(&)并(|)差(-)等操作,比如,要比较cet4.txt和cet6.txt两个文件,获得六级特有词汇:
f=open('cet4.txt') #默认为打开模式
cet4=f.readlines()
f.close()
f=open('cet6.txt')
cet6=f.readlines()
f.close()
seta=set(cet6)
setb=set(cet4)
setc=seta-setb#对seta、setb取差集,即只在seta中而未在setb中出现的元素所组成的集合。
new_cet6=list(setc) #把setc变成列表,方便输出到文本
f=open('new_cet6.txt', 'w') #写入文件
f.writelines(new_cet6) #写入六级特有词汇
f.close()
help(set)可查询到更多的集合操作。
查询单词、筛选词表
字典dict这种结构在做词典时比较有用,相当于两组列表:保存单词的键列表(不可重复)、保存解释的值列表。
字典一般用{}表示,键值间用“:”分隔,如:d={'I':'我', 'you':'你'}。如果要查询you,可通过d['you']获得you的解释。
直接建立字典规模不会太大,通常从一定格式的文件(比如每行格式为:词语\t解释)中创建,
d = dict()#建立一个空字典,也可使用{}建立。
f = open('a.txt', 'r')
for line in f: #每次从f中读入一行
line=line.rstrip('\n')#去除行尾的换行符
word, mean = line.split('\t', 1)#将line用\t进行分割,最多分一次变成两块,保存到word和mean中去
d[word]=mean
f.close()
若要将建好的字典d按序输出文件中,可使用iteritems取出所有的键和值,对它进行排序,然后按序取出所有的值
f = open('a.txt', 'w')
for word, mean in sorted(d.itertems()):
print >>f, word+'\t'+mean #输出时使用\t分隔单词和解释,然后换行
f.close()
若只有输出d中部分词和解释制作词典,比如只输出cet4_words列表中的词:
cet4_words = ['a', 'the']
cet4_words.sort() #对cet4_words进行排序
f = open('a.txt', 'w')
for word in sorted(cet4_words):
print >>f, word+'\t'+d[word] #输出时使用\t分隔单词和解释,然后换行
f.close()
help(dict)可查询更多字典操作。