您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 经营企划 > 用Python做文本处理 第一章
用Python作文本处理/第一章目录1第一章--Python基础o1.1第一节--技巧和形式1.1.1主题--在文字处理里使用高阶函数1.1.1.1练习:组合函数的应用1.1.2主题--Python数据类型的特殊性1.1.3主题--基础数据类1.1.3.1BUILTIN--对象:新式数据类型原型1.1.3.2BUILTIN--file:文件对象的新式类1.1.3.3BUILTIN--int:整数的新式类1.1.3.4BUILTIN--long:长整数的新式类1.1.3.5BUILTIN--float:浮点数的新式类1.1.3.6BUILTIN--complex:复数的新式类1.1.3.7模块--UserDict:包装字典对象的类1.1.3.8BUILTIN--dict:字典对象的新式类1.1.3.9模块--UserList:包装列表对象的类1.1.3.10BUILTIN--list:列表对象的新式类1.1.3.11BUILTIN--tuple:元组对象的新式类1.1.3.12模块--UserString:包装字符串对象的类1.1.3.13BUILTIN--str:字符串对象的新式类1.1.3.13.1练习:格式化字符串1.1.3.13.2练习:在大文件里行操作第一章--Python基础本章讨论Python处理文本的能力。Python语法和语义可以参考附录A或GuidovanRossum的_PythonTutorial_在。这里的重点不是Python语言介绍,但也没有特别关注文本处理。在1.1,我会关注一些Python语言的编程技术,并不适合Python初学者。编程技术的讨论着重于适用文字处理的情况--其他编程任务本书不会详细讨论。在1.2,我会介绍Python的标准库在文字处理程序里的应用。有些Python标准库模块是远远不适合文字处理的,在这方面你可能不会使用它们。这种边缘的模块我只会非常简单的作一两行说明。更详细的资料请翻看Python的文档。第一节--技巧和形式主题--在文字处理里使用高阶函数这第一个主题富有挑战性。如果是首次接触高阶函数对于不熟悉这方面的Python程序员来说有点困难。不要过于害怕这个困难--您可以了解到其他书里没有的东西。如果函数式编程概念你不熟悉,我建议你先看附录A,特别是其中最后一节的介绍。在文字处理中,一个经常的动作就是处理一系列句子,这些句子有一定的相似性。多数情况下,这些句子是用换行分隔,但有时也会用其他的形式。此外,Python从文件里按行读取在不同平台可能会有所差异。显然,这样的分块还没有完全统一,会包含不同的数据。但在这里我们先不考虑这个,我们假设每个分块句都包含了正确有用的资料。举例而言,我们想选择那些符合我们要求的行文字,其标准是'isCond()':#*----------命令行式风格的行选择-----------------------#selected=[]#收集可用的行fp=open(filename):forlineinfp.readlines():#Python2.2-forlineinfp:ifisCond(line):#(2.2版本这里是惰性读取)selected.append(line)delline#清除不用的名称这样读取几行没有任何-错误-(效率问题参看[xreadlines])。但阅读这样的程序会多花几秒钟。在我看来,即使是这么一小段程序也不符合-简单-的设计思想,即使它的运作确实是这样的。'line'这个变量略显多余(不光要考虑循环以后它的保留价值,同时循环的每一步都要给它赋值)。在函数式风格里,我们可以写的很简单:#*----------函数式风格的行选择-------------------------#selected=filter(isCond,open(filename).readlines())#Py2.2-filter(isCond,open(filename))在具体应用里,一个经常做的操作就是处理一个有很多行的日志文件。各式各样的应用程序都会产生日志文件,最常见的是那些导致系统变化的应用程序需要纪录每一次操作。例如,Python的Windows安装程序会产生一个'INSTALL.LOG',其中包含了安装中各个步骤的清单。以下是从我的电脑复制的一个这个文件:#------------INSTALL.LOG样本--------------------------#Title:Python2.2Source:C:\DOWNLOAD\PYTHON-2.2.EXE|02-23-2002|01:40:54|7074248MadeDir:D:\Python22FileCopy:D:\Python22\UNWISE.EXE|05-24-2001|12:59:30||...RegDBKey:Software\Microsoft\Windows\CurrentVersion\Uninstall\Py...RegDBVal:Python2.2FileCopy:D:\Python22\w9xpopen.exe|12-21-2001|12:22:34||...MadeDir:D:\PYTHON22\DLLsFileOverwrite:C:\WINDOWS\SYSTEM\MSVCRT.DLL||||295000|770c8856RegDBRoot:2RegDBKey:Software\Microsoft\Windows\CurrentVersion\AppPaths\Py...RegDBVal:D:\PYTHON22\Python.exeShellLink:C:\WINDOWS\StartMenu\Programs\Python2.2\UninstallPy...LinkInfo:D:\Python22\UNWISE.EXE|D:\PYTHON22||0|1|0|ShellLink:C:\WINDOWS\StartMenu\Programs\Python2.2\Python...LinkInfo:D:\Python22\python.exe|D:\PYTHON22|D:\PYTHON22\...你可以看到,每一个行动记录都是那几种类型。如果要处理每种不同类型的行动纪录(每种类型会有不同的数据字段结构),最简单的是用布尔函数来确定每一行的类型,例如:#*-------每一行的布尔判定函数---------------------------#defisFileCopy(line):returnline[:10]=='FileCopy:'#或者使用line.startswith(...)defisFileOverwrite(line):returnline[:15]=='FileOverwrite:'字符串函数`.startswith()`不容易出错。用一种稍微紧凑的函数式编程风格,您可以写成这样:#*-----------函数式风格判定----------------------------#isRegDBRoot=lambdaline:line[:11]=='RegDBRoot:'isRegDBKey=lambdaline:line[:10]=='RegDBKey:'isRegDBVal=lambdaline:line[:10]=='RegDBVal:'选择某种类型的行可以这样做:#*-----------Selectlinesthatfillpredicate----------#lines=open(r'd:\python22\install.log').readlines()regroot_lines=filter(isRegDBRoot,lines)但是,如果你要采用多种标准来选择,那函数式风格会成为累赘。例如假设你对所有RegDB行有兴趣,你可以写一个新的函数过滤器:#*---------------FindtheRegDBlines------------------#defisAnyRegDB(line):ifline[:11]=='RegDBRoot:':return1elifline[:10]=='RegDBKey:':return1elifline[:10]=='RegDBVal:':return1else:return0#最好使用line.startswith(...)每个条件都写一个函数会产生大量的函数。更重要的是,每个函数都需要去写,而且还增加了bug产生的机会。用组合的方式,您可以用几个过滤器组合成一种新的过滤条件。例如:#*-------------用2种条件来过滤------------------------#shortline=lambdaline:len(line)25short_regvals=filter(shortline,filter(isRegDBVal,lines))在这个例子中,我们依靠先前定义的过滤器函数。在'shortline()'或'isRegDBVal()'产生的任何错误都会影响这个过滤,'isShortRegVal()'第三方过滤器函数则不会对这个产生影响。使用嵌套的filter会比较难以阅读--尤其是数量超过两个以上。对同一个字符串做若干处理使用`map()`也是同样会嵌套多层。例如,假设您希望把一行由空格分割的小写文字翻转组合起来并改为大写,创建这样的函数很简单,他们可以嵌套在`map()`里:#*------------一行文字同时多种转换---------------------#defflip(s):returns[::-1]normalize=lambdas:''.join(s.split())cap_flip_norms=map(str.upper,map(flip,map(normalize,lines)))这种类型的`map()`或`filter()`会难以阅读,应当避免。此外,有时会交替使用`map()`和`filter()`,使问题更加严重。例如,假设您要对每一行做一些处理,同时还要对这些行做一些判断。为了避免这种问题,许多程序员会改回那种更详细的命令行式编码风格,例如包装几个循环再使用一些保存中间结果的临时变量。在函数式编程风格里是可以避免这种过多嵌套的。关键是要有几个聪明的高阶组合函数。一般而言,高阶函数会需要函数作为参数并且返回的结果也是一个函数对象。一阶函数会需要一些数据作为参数并产生一种数据结构作为返回值(典型的结构会像一个list或dict)。与此相反,更高阶的函数的inputs和outputs会是某种函数对象--通常在最终某处才开始真正流程处理运作。高阶函数的一个典型例子就是一个-函数工厂-:这个函数(或类)会返回一个函数或是几个函数的包裹器,这些返回值都会包含某种配置。做一个HelloWorld例子,一个简单的函数工厂可以是一个adder工厂。一个加法器工厂只是为了表明可以做什么,它并没有什么真正的用途。几乎每一个解释函数工厂都会使用这样的一个例子,如:defadder_factory(n):...returnlambdam,n=n:m+n...add10=adder_factory(10)add10functionlambdaat0x00FB0020add10(4)14add10(20)30add5=adder_factory(5)add5(4)9对于文字处理来说,简单的函数工厂都不如高阶组合函数。高阶组合函数需要几个(通常是一阶)函数作为参数并返回一个新的函数,这个函数会把几个具体的函数组合起来。下面是一个简单的高阶组合函数表,只需要令人惊讶的几行:#-------------------combinatorial.py-------------------#fromo
本文标题:用Python做文本处理 第一章
链接地址:https://www.777doc.com/doc-6016601 .html