您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 管理学资料 > 用Python作文本处理 第二章 -- 基本的字符串运用
用Python作文本处理/第二章目录1第一节--常用的操作2主题--快速排序3主题--排版4主题--处理字段5主题--字词数统计6主题--以二进制数据传送ASCII码信息7主题--词频统计第一节--常用的操作主题--快速排序排序是文字处理中大多数任务的关键所在。幸运的是,在Python里,使用`[].sort`的效率还不错。此外,在列表的任何不同对象都可以排序而不需要像C语言那样需要统一的元素(对于混合复数和Unicode字符串的列表排序在最近的几个Python版本里会触发'TypeError'异常)。参考:[complex]+++列表排序的顺序有一种自然顺序,特别是不同类型混合的排序顺序都是Python的默认顺序。很多时候,你需要特定的顺序。特别是对于文本里的行做排序往往需要的不是简单的字母顺序。通常一行里有用的信息起始位置并不是第一个字符:人名里的姓往往是第二个单词;服务器日志里IP地址可能固定在某个字段;金额合计可能在每一行的第70列等等。只使用默认排序这些内容只会毫无意义。列表排序`[].sort()`支持自定义比较函数参数。这个比较函数的功能是返回-1则表示前者排在后者之前,返回0则表示二者顺序相同,返回1则表示后者排在前者之前。内置函数`cmp()`就是`[].sort()`的默认比较函数(在速度上'lst.sort()'远远超过'lst.sort(cmp)')。对于不太长的列表使用自定义比较函数可以快速的解决问题。在很多情况下,甚至可以直接使用一个'lambda'表达式来完成任务。说到速度,使用自定义比较函数效率会很低。部分原因是Python的函数调用开销,函数本身也会增加花费的时间。不过有一种技术“Schwartzian转换”可以加速这种自定义排序。Schwartzian转换是兰德尔施瓦兹在Perl中最先开始使用的,但其中的技巧同样适用于Python。使用Schwartzian转换主要包括三个步骤,(准确的来说这是Guttman-Rosler转换(GRT),同样基于Schwartzian转换):1.将列表转换为可以用默认排序的列表。2.使用`[].sort()`排序。3.转回原先的格式。这项技术的主要作用是花费仅仅O(2N)转换就可以使用默认的O(NlogN)排序。如果任务里排序时间是主要因素的话,使用这项技术将大大提高效率(唯一的限制就是转换花费的时间不会很多)。下面是一个简单的例子。排序比较方式是比较每一行的第四个单词。有的行单词数少于4个。测试文件约20,000行(1兆左右)使用Schwartzian转换排序花费不到2秒,而使用自定义比较函数则花费12秒以上(排序结果一样)。确切时间不会很准确,但很明显效率提高了6倍。#----------schwartzian_sort.py----------##-测试按第四个单词排序的速度#-如果两行都有4个以上单词,则按照第4个第5个。。来排序#-没有4个单词的行排在有4个单词的行后面#-没有4个单词的行之间按照默认顺序排列importsys,string,timewrerr=sys.stderr.write#-自定义比较函数deffourth_word(ln1,ln2):lst1=string.split(ln1)lst2=string.split(ln2)#--比较4个单词以上的行iflen(lst1)=4andlen(lst2)=4:returncmp(lst1[3:],lst2[3:])#--少于4个单词的行排在后面eliflen(lst1)=4andlen(lst2)4:return-1#--少于4个单词的行排在后面eliflen(lst1)4andlen(lst2)=4:return1else:#默认顺序returncmp(ln1,ln2)#-不计算读取时间lines=open(sys.argv[1]).readlines()#-计时使用自定义比较函数排序start=time.time()lines.sort(fourth_word)end=time.time()wrerr(Customcomparisonfuncin%3.2fsecs\n%(end-start))#open('tmp.custom','w').writelines(lines)#-不计算读取时间lines=open(sys.argv[1]).readlines()#-计时Schwartzian转换排序start=time.time()forninrange(len(lines)):#开始转换lst=string.split(lines[n])iflen(lst)=4:#把排序内容放在前面lines[n]=(lst[3:],lines[n])else:#少于4个单词的行排在后面lines[n]=(['\377'],lines[n])lines.sort()#排序forninrange(len(lines)):#转换回原先内容lines[n]=lines[n][1]end=time.time()wrerr(Schwartziantransformsortin%3.2fsecs\n%(end-start))#open('tmp.schwartzian','w').writelines(lines)这只有一个特别的例子,但读者应该能够用任何形式来使用这种技术,特别是对于大文件。主题--排版虽然使用ASCII文本作为通讯格式并不好--通常不会很复杂文件不会很大--但其生命力还是很强的。README文件,HOWTO文件,电子邮件,新闻组,包括本书都仍然是使用ASCII码文本(至少原文加工技术通常是很有价值的)。此外,许多像HTML和Latex的格式往往也需要手动修改,清晰的排版是非常重要的。段落排版对于文本文件来说是极为常见的工作。Python2.3增加了[textwrap]模块做一些有限的排版工作。在大多数情况下,这项工作可以使用文本编辑器来完成。不过,有时候自动化排版会更方便。这项工作很简单,比较奇怪的是,Python没有相应的标准模块功能实现这一点。有一个`formatter.DumbWriter`类和`formatter.AbstractWriter`抽象类可以用于此项工作。相关讨论在第5章,坦率地说,使用这些类需要大量的定制工作而且很复杂,往往不适合用于解决手头的任务。下面是一种简单的解决办法,可以当作命令行工具(从标准输入读取和输出到标准输出),或用于较大的应用程序。#----------reformat_para.py----------##简单排版。主要用于左右对齐。LEFT,RIGHT,CENTER='LEFT','RIGHT','CENTER'defreformat_para(para=,left=0,right=72,just=LEFT):words=para.split()lines=[]line=word=0end_words=0whilenotend_words:iflen(words[word])right-left:#过长的单词line=words[word]word+=1ifword=len(words):end_words=1else:#收集一行可以容纳的单词whilelen(line)+len(words[word])=right-left:line+=words[word]+''word+=1ifword=len(words):end_words=1breaklines.append(line)line=ifjust==CENTER:r,l=right,leftreturn'\n'.join([''*left+ln.center(r-l)forlninlines])elifjust==RIGHT:return'\n'.join([line.rjust(right)forlineinlines])else:#leftjustifyreturn'\n'.join([''*left+lineforlineinlines])if__name__=='__main__':importsysiflen(sys.argv)4:printPleasespecifyleft_margin,right_marg,justificationelse:left=int(sys.argv[1])right=int(sys.argv[2])just=sys.argv[3].upper()#排版每一段forpinsys.stdin.read().split('\n\n'):printreformat_para(p,left,right,just),'\n'留给读者一些改进任务。例如您可能需要首行缩进。或者有些段落需要的格式不适合用此排版(例如题头等等)。具体的应用程序还可能需要确定如何分段等等。主题--处理字段数据表,DBMS,日志文件以及平面数据库往往在每行放置同样的纪录,每条记录有相同的字段。通常这些字段要么是用分割符间隔要么是用固定位置来存放。分析这些记录的结构很容易,进行表格计算上也同样很简单。对于各种文本结构数据,可以使用几乎相同的代码来做处理。下面的例子中提供了一种通用的框架来处理结构化文本。#----------fields_stats.py----------##处理文本数据库里的多个字段importoperatorfromtypesimport*fromxreadlinesimportxreadlines#需要Python2.1,提高效率#2.1以下使用.readline()#--格式常量DELIMITED=1FLATFILE=2#--一些简单的处理过程(使用函数式风格)nillFunc=lambdalst:NonetoFloat=lambdalst:map(float,lst)avg_lst=lambdalst:reduce(operator.add,toFloat(lst))/len(lst)sum_lst=lambdalst:reduce(operator.add,toFloat(lst))max_lst=lambdalst:reduce(max,toFloat(lst))classFieldStats:统计资料text_db可以是字符串(包括Unicode字符串)或文件类对象style有2种格式(DELIMITED,FLATFILE)分隔符或位置默认使用分隔符格式column_positions位置列表,第一列的位置为1。例如:(1,7,40)表示3个字段,起始位置分别为1,7,40field_funcs是字典,储存需要处理的字段和对应处理过程。例如:{1:avg_lst,4:sum_lst,5:max_lst}表示对第一个字段做求平均值处理对第四个字段做合计处理,对第5个字段求最大值其他字段不做处理。def__init__(self,text_db=,style=DELIMITED,delimiter=',',column_positions=(1,),field_funcs={}):self.text_db=text_dbself.style=styleself.delimiter=delimiterself.column_positions=column_positionsself.field_funcs=field_funcsdefcalc(self):计算#--第一步先建立列表的列表来存放数据。used_cols=self.field_funcs.keys()used_cols.sort()#:不使用column[0]columns=[]forninrange(1+used_cols[-1]):#提示:这里可以使用'[[]]*num'来代替columns.append([])#--第二步生成需要计算的列表数据#text_db是字符串对象iftype(self.text_db)in(Str
本文标题:用Python作文本处理 第二章 -- 基本的字符串运用
链接地址:https://www.777doc.com/doc-4583613 .html