用Python做文本处理第一章_第1页
用Python做文本处理第一章_第2页
用Python做文本处理第一章_第3页
用Python做文本处理第一章_第4页
用Python做文本处理第一章_第5页
已阅读5页,还剩28页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、用Python作文本处理/第一章目录 1第一章 - Python基础o 1.1第一节 - 技巧和形式 1.1.1主题 - 在文字处理里使用高阶函数 练习:组合函数的应用 1.1.2主题 - Python数据类型的特殊性 1.1.3主题 - 基础数据类 BUILTIN - 对象: 新式数据类型原型 BUILTIN - file: 文件对象的新式类 BUILTIN - int: 整数的新式类 BUILTIN - long: 长整数的新式类 BUILTIN - float: 浮点数的新式类 BUILTI

2、N - complex: 复数的新式类 模块 - UserDict: 包装字典对象的类 BUILTIN - dict: 字典对象的新式类 模块 - UserList: 包装列表对象的类 0BUILTIN - list: 列表对象的新式类 1BUILTIN - tuple: 元组对象的新式类 2模块 - UserString: 包装字符串对象的类 3BUILTIN - str: 字符串对象的新式类 3.1练习:格式化字符串 3.2练习:在大文件里行操作第一章 - Pyth

3、on基础本章讨论Python处理文本的能力。Python语法和语义可以参考附录A或Guido van Rossum的_Python Tutorial_在/doc/current/tut/tut.html。这里的重点不是Python语言介绍,但也没有特别关注文本处理。在1.1,我会关注一些Python语言的编程技术,并不适合Python初学者。编程技术的讨论着重于适用文字处理的情况-其他编程任务本书不会详细讨论。在1.2,我会介绍Python的标准库在文字处理程序里的应用。有些Python标准库模块是远远不适合文字处理的,在这方面你可能不会使用它们。这种边缘的模块

4、我只会非常简单的作一两行说明。更详细的资料请翻看Python的文档。第一节 - 技巧和形式主题 - 在文字处理里使用高阶函数这第一个主题富有挑战性。如果是首次接触高阶函数对于不熟悉这方面的Python程序员来说有点困难。不要过于害怕这个困难-您可以了解到其他书里没有的东西。如果函数式编程概念你不熟悉,我建议你先看附录A,特别是其中最后一节的介绍。在文字处理中,一个经常的动作就是处理一系列句子,这些句子有一定的相似性。多数情况下,这些句子是用换行分隔,但有时也会用其他的形式。此外,Python从文件里按行读取在不同平台可能会有所差异。显然,这样的分块还没有完全统一,会包含不同的数据。但在这里我们

5、先不考虑这个,我们假设每个分块句都包含了正确有用的资料。举例而言,我们想选择那些符合我们要求的行文字,其标准是isCond(): #*- 命令行式风格的行选择 -# selected = # 收集可用的行 fp = open(filename): for line in fp.readlines(): # Python2.2 - for line in fp: if isCond(line): # (2.2版本这里是惰性读取) selected.append(line) del line # 清除不用的名称这样读取几行没有任何 -错误-(效率问题参看xreadlines)。但阅读这样的程序会多

6、花几秒钟。在我看来,即使是这么一小段程序也不符合 -简单- 的设计思想,即使它的运作确实是这样的。line这个变量略显多余(不光要考虑循环以后它的保留价值,同时循环的每一步都要给它赋值)。在函数式风格里,我们可以写的很简单: #*- 函数式风格的行选择 -# selected = filter(isCond, open(filename).readlines() # Py2.2 - filter(isCond, open(filename)在具体应用里,一个经常做的操作就是处理一个有很多行的日志文件。各式各样的应用程序都会产生日志文件,最常见的是那些导致系统变化的应用程序需要纪录每一次操作。例

7、如,Python的Windows安装程序会产生一个INSTALL.LOG,其中包含了安装中各个步骤的清单。以下是从我的电脑复制的一个这个文件: #- INSTALL.LOG 样本 -# Title: Python 2.2 Source: C:DOWNLOADPYTHON-2.2.EXE | 02-23-2002 | 01:40:54 | Made Dir: D:Python22 File Copy: D:Python22UNWISE.EXE | 05-24-2001 | 12:59:30 | | . RegDB Key: SoftwareMicrosoftWindowsCurrentVersi

8、onUninstallPy. RegDB Val: Python 2.2 File Copy: D:Python22w9xpopen.exe | 12-21-2001 | 12:22:34 | | . Made Dir: D:PYTHON22DLLs File Overwrite: C:WINDOWSSYSTEMMSVCRT.DLL | | | | | 770c8856 RegDB Root: 2 RegDB Key: SoftwareMicrosoftWindowsCurrentVersionApp PathsPy. RegDB Val: D:PYTHON22Python.exe Shell

9、 Link: C:WINDOWSStart MenuProgramsPython 2.2Uninstall Py. Link Info: D:Python22UNWISE.EXE | D:PYTHON22 | | 0 | 1 | 0 | Shell Link: C:WINDOWSStart MenuProgramsPython 2.2Python . Link Info: D:Python22python.exe | D:PYTHON22 | D:PYTHON22.你可以看到,每一个行动记录都是那几种类型。如果要处理每种不同类型的行动纪录(每种类型会有不同的数据字段结构),最简单的是用布尔函数

10、来确定每一行的类型,例如: #*- 每一行的布尔判定函数 -# def isFileCopy(line): return line:10=File Copy: # 或者使用 line.startswith(.) def isFileOverwrite(line): return line:15=File Overwrite:字符串函数.startswith()不容易出错。用一种稍微紧凑的函数式编程风格,您可以写成这样: #*- 函数式风格判定 -# isRegDBRoot = lambda line: line:11=RegDB Root: isRegDBKey = lambda line:

11、line:10=RegDB Key: isRegDBVal = lambda line: line:10=RegDB Val:选择某种类型的行可以这样做: #*- Select lines that fill predicate -# lines = open(rd:python22install.log).readlines() regroot_lines = filter(isRegDBRoot, lines)但是,如果你要采用多种标准来选择,那函数式风格会成为累赘。例如假设你对所有RegDB行有兴趣,你可以写一个新的函数过滤器: #*- Find the RegDB lines -# d

12、ef isAnyRegDB(line): if line:11=RegDB Root: return 1 elif line:10=RegDB Key: return 1 elif line:10=RegDB Val: return 1 else: return 0 # 最好使用line.startswith(.)每个条件都写一个函数会产生大量的函数。更重要的是,每个函数都需要去写,而且还增加了bug产生的机会。用组合的方式,您可以用几个过滤器组合成一种新的过滤条件。例如: #*- 用2种条件来过滤 -# shortline = lambda line: len(line) def adder

13、_factory(n): . return lambda m, n=n: m+n . add10 = adder_factory(10) add10 function at 0x00FB0020 add10(4) 14 add10(20) 30 add5 = adder_factory(5) add5(4) 9对于文字处理来说,简单的函数工厂都不如高阶组合函数。高阶组合函数需要几个(通常是一阶)函数作为参数并返回一个新的函数,这个函数会把几个具体的函数组合起来。下面是一个简单的高阶组合函数表,只需要令人惊讶的几行: #- combinatorial.py -# from operator im

14、port mul, add, truth apply_each = lambda fns, args=: map(apply, fns, args*len(fns) bools = lambda lst: map(truth, lst) bool_each = lambda fns, args=: bools(apply_each(fns, args) conjoin = lambda fns, args=: reduce(mul, bool_each(fns, args) all = lambda fns: lambda arg, fns=fns: conjoin(fns, (arg,) b

15、oth = lambda f,g: all(f,g) all3 = lambda f,g,h: all(f,g,h) and_ = lambda f,g: lambda x, f=f, g=g: f(x) and g(x) disjoin = lambda fns, args=: reduce(add, bool_each(fns, args) some = lambda fns: lambda arg, fns=fns: disjoin(fns, (arg,) either = lambda f,g: some(f,g) anyof3 = lambda f,g,h: some(f,g,h)

16、compose = lambda f,g: lambda x, f=f, g=g: f(g(x) compose3 = lambda f,g,h: lambda x, f=f, g=g, h=h: f(g(h(x) ident = lambda x: x即使只有十几行,这些组合函数就足以提供方便了。让我们看看我们如何使用这些高阶函数来简化一些较早的例子。和上面采用一样的函数命名: #- 一些高阶函数的使用例子 -# # Dont nest filters, just produce func that does both # 不需要嵌套filter,只需要用both来组合条件 short_re

17、gvals = filter(both(shortline, isRegVal), lines) # Dont multiply ad hoc functions, just describe need # 不需要增加函数,只需要描述需求 regroot_lines = filter(some(isRegDBRoot, isRegDBKey, isRegDBVal), lines) # Dont nest transformations, make one combined transform # 不需要嵌套转换,只需要建立一个组合 capFlipNorm = compose3(upper,

18、flip, normalize) cap_flip_norms = map(capFlipNorm, lines)在例子中,我们使用组合函数capFlipNorm非常有可读性。相应的map()行只是-单一的表示-执行在所有行上做这个处理。这个例子已经说明了组合函数的灵活性。通过浓缩几个操作就能代替以前好几个map()嵌套,我们还可以把这个组合过的操作运用到程序其他地方。作为一个经验,我建议不要在任何一个代码行上使用一个以上的filter()和map()。如果这些list应用函数需要嵌套,应该使用一个保存中间结果的名称变量来增加可读性。连续的函数式编程风格读起来会比较像命令行式风格-不过奇妙的是

19、Python允许无缝组合不同的编程风格。例如: #*- 限制map()/filter()的嵌套层数 -# intermed = filter(niceProperty, map(someTransform, lines) final = map(otherTransform, intermed)任何连续嵌套的filter()或map()程序都可以用高阶组合函数转换成单一的函数。而这些产生的步骤也只需要很少几步。在总代码数量上抵消了定义组合函数的消耗。总之,函数式风格的代码通常只有命令行式风格大约一半的长度(越少的代码一般意味着有相对较少的bug)。组合函数还有一个好处是可以提供一个完整的布尔代

20、数应用,而不需要使用明显的调用(在这个意义上combinatorial.py使用operator.add和operator.mul不是偶然的)。例如,一个简单的运算就可以表示复杂的逻辑关系,例如: #*- 使用值运算的简单布尔表达式 -# satisfied = (this or that) and (foo or bar)在文字处理上,这些判断函数产生的真值往往是一段需要处理的文字,例如: #*- 函数返回值的逻辑运算 -# satisfied = (thisP(s) or thatP(s) and (fooP(s) or barP(s)在上面这个表达式中,一些判断函数对相同的字串(或其他东

21、西)进行判断,有逻辑关系的结果就会被计算。这表达式本身也说明了这种逻辑关系。清楚的命名-特别是如果你想在参数相同的前提上多次运算的话-将可以方便的创建一个有实际功能的表达式: #*- 组合函数的逻辑运算 -# satisfiedP = both(either(thisP,thatP), either(fooP,barP)利用组合技术创建的判断函数同样可以应用在其他函数里: #*- 使用组合的布尔函数 -# selected = filter(satisfiedP, lines)练习:组合函数的应用模块combinatorial.py提供了一些最常见的高阶组合函数。但是,还有加强的余地。创建一个

22、个人高阶函数库来充实您当前的文本处理库。题目:1. combinatorial.py里定义的一些函数严格地说不是组合函数。在精确的意义上说,一个组合函数应该用一个或几个函数作为参数并返回一个或多个组合后的函数对象。哪些函数不是“严格”的组合函数,并确定这些函数的返回值到底是什么样的东西。2. 函数both()和and_()看上去很相似。但是他们有所不同,and_()比较像Python里的and,可以提前中断运算。例如: f = lambda n: n*2 10 g = lambda n: 100/n 10 and_(f,g)(5) 1 both(f,g)(5) 1 and_(f,g)(0) 0

23、 both(f,g)(0) Traceback (most recent call last): .and_()这种形式可以用第一个函数的结果来提前终止运算。如果第一个函数返回一个假值,那第二个函数就不会计算。 a. 建立一个相似的or_() b. 建立同样可以提前终止运算的shortcut_all()和shortcut_some() c. 阐述那些情况最好使用不提前中断的组合函数而不使用会提前中断的函数3. 解释ident()的真正作用提示:假设你有几行文字,其中一些行可能是空字符串。怎么设计过滤器可以找到所有开始为#的行?4. not_()可能应该是一个组合库的扩展功能。我们可以这样定义:

24、 not_ = lambda f: lambda x, f=f: not f(x)探索一下not_()函数对组合程序有哪些帮助。5. apply_each()被用在建立其他组合函数。不过它也有一些实际用途。例如: apply_each(map(adder_factory, range(5),(10,) 10, 11, 12, 13, 14探索一下apply_each()如何简化文本的多次处理。6. 不像all()和some(),compose()和compose3()只能使用固定数目的函数做参数。建造一个可以使用任何数目的函数为参数的合成函数。7. 还有什么适合文本处理的高阶组合函数?考虑一下

25、常用的一阶函数。主题 - Python数据类型的特殊性Python有丰富的标准数据类型-附录A讨论各种内置的类型。与此同时,Python编程的一个重要原则让其他语言的程序员觉得类型不是很重要。根据Python的“普遍多态性原则”(我自己创造的名词),对象能“作什么”比“是什么”重要。另一种对这个原则的解释是:如果它像一个鸭子而且叫声也像鸭子,那就把它当作是一只鸭子。一般而言,多态的设计思想是让同样的函数可以在不同的类型上工作。在C+或Java,例如,您可以使用特化方式来重载某些操作以适用于多种数据类型(根据需求有所不同)。例如: #- C+ 标示型多态性 -# #include class P

26、rint public: void print(int i) printf(int%dn, i); void print(double d) printf(double%fn, d); void print(float f) printf(float%fn, f); ; main() Print *p = new Print(); p-print(37); /* - int 37 */ p-print(37.0); /* - double 37. */ 最直接的Python翻译就是使用参数类型检查。就像这样: #- Python 标示型 多态性 -# def Print(x): from ty

27、pes import * if type(x) is FloatType: print float, x elif type(x) is IntType: print int, x elif type(x) is LongType: print long, x这种函数不是Python的风格。如果你需要这类明确的类型检查,那你可能还不明白的要真正解决的问题!你感兴趣的(通常)是x是什么类型,而不是x可以做什么你需要它来执行的任务(它是哪种东西并不值得关心)。PYTHON的多态性:多态性一个最常见的情况是用于类似file的对象。有许多对象,做的事情就是file做的事情,如用 urllib, cSt

28、ringIO, zipfile建立的对象。各种对象的操作和实际的file操作一样:一些对象可以读,一些可以写,还有一些可以定位等等。很多情况下,您没有必要实现file-like的每一种能力-只要确保特定对象具有你实际需要的一些功能就足够了。这里有个典型的例子。我有一个模块,使用DOM处理XML文件,我想让用户可以使用多种方式来指派XML数据源:使用文件名称,使用一个包含XML的file-like对象,使用已经建立DOM的对象(例如XML标准库建立的对象)。我还没有完全考虑到一些其他地方(如关系型数据库,网络数据等等)。为了看一下这个数据源可以“做什么”,我在两处检查对象拥有的能力: #- Py

29、thon 功能型多态性 -# def toDOM(xml_src=None): from xml.dom import minidom if hasattr(xml_src, documentElement): return xml_src # 已经有DOM对象 elif hasattr(xml_src,read): # 看起来可以读数据 return minidom.parseString(xml_src.read() elif type(xml_src) in (StringType, UnicodeType): # 这是个文件名 xml = open(xml_src).read() re

30、turn minidom.parseString(xml) else: raise ValueError, Must be initialized with + filename, file-like object, or DOM object即使是简单的数字似乎也有各种不同的功能。至于其他对象,你不应该关心他代表的是什么,而是他可以做什么。当然,作为一种确认对象功能的方式是可以的,往往在使用内建函数complex(),dict(),float(),int(),list(),long(),str(),tuple()和unicode()时需要这么做。所有这些函数都会努力把任何东西转换成需要的类型

31、来建立一个真正的实体。这种转换通常不是必须的。例如,要删除数字的不精确部分-也许是因为他们的测量精度有限。对于整数-int或long-你可能需要去掉一些低位数字,对于分数你可能需要四舍五入到一个精度。不应该测试值的类型,您应该寻找值的功能。Python里一个通常的方式是用来测试能做什么,然后捕获任何错误再尝试其他的方法。下面是一个简单的例子: #- 检查值能做什么 -# def approx(x): # 2.2+需要有int的能力 if hasattr(x,_and_): # 支持位操作 return x & 0x0FL try: # 支持real/imag return (round(x.r

32、eal,2)+round(x.imag,2)*1j) except AttributeError: return round(x,2)强化对象:普遍多态性可以实现的原因是Python很容易创建和基本类型相似的对象。file-like对象就是这样,你有没有想过一个文件对象需要有精确的数据类型。即使像基本数据类型-数字,字符串,列表和字典-也是很容易模仿的。模仿基本数据类型有两个细节要注意。最重要的问题是要理解一个对象的能力-包括他们的语法结构-这通常是掌握实现魔术性的方法,_或_是隐藏在背后的细节。任何对象都可以像一个基本的数据类型一样使用它所提供的操作函数。核心就是一个基本的数据类型仅仅是一个

33、对象,只是他有专门优化的完善的魔术性操作方式。第二个细节关注的是你如何实现这种魔术性-更确切地说,如何最好地利用现有的资源。没有人阻止你编写任何基本数据类型的个人版本,不过这只是增加麻烦。有不少细节,你可以用简单的方法来获得您想要的功能。在所有非古代版本的Python里,标准库都提供了纯的Python模块 UserDict, UserList和 UserString作为样式,来让你定义需要的数据类型。您可以继承一个适当的父类来获得这些魔术性的能力。但是tuple,int,float等还没有直接使用的样本。Python2.2以上版本有更好的选择可用。新式Python类可以让你继承所有基本数据类型

34、在C代码里实现的功能。此外,这些基本类自身也可以被调用来建造对象:int(),list(),unicode()等等。新式类型有很多秘密和微妙设计结构,但你通常并不需要担心这些。您所需要知道的是,一个继承 string的类型比一个继承 UserString的快,同样 list与 UserList和 dict与 UserDict也是一样(最好让你的所有脚本运行在最新的Python版本下)。自定义数据类型,不需要专门的设计。你可以自由地根据基本数据类型选择需要的功能来创造特定的类型。当然,在实践中,你为此创造的自定义数据类型会包含一些没有魔术性的操作方法,或者是你要用多种基本类型来组合他们的神奇功能

35、。例如,下面这个自定义数据类型,既可以让approx()函数来调用,还可以有自身特有的功能: class I: . def _init_(self, i): self.i = i . def _and_(self, i): return self.i & i . def err_range(self): . lbound = approx(self.i) . return Value: %d,%d)% (lbound, lbound+0x0F) . i1, i2 = I(29), I(20) approx(i1), approx(i2) (16L, 16L) i2.err_range() Va

36、lue: 16, 31)尽管支持了一个额外的功能,并且能够成功让approx()函数使用,I还不是一个用途很广的数据类型。如果您尝试使用加法或除法以及乘法,你会得到一个TypeError。由于没有所谓的 UserInt模块,老Python版本您需要落实每一个神奇功能函数。利用新的Python2.2+,你可以直接从int数据类型获得支持。部分实现可能是这样: class I2(int): # New-style fuzzy integer . def _add_(self, j): . vals = map(int, approx(self), approx(j) . k = int._add_

37、(*vals) . return I2(int._add_(k, 0x0F) . def err_range(self): . lbound = approx(self) . return Value: %d,%d)%(lbound,lbound+0x0F) . i1, i2 = I2(29), I2(20) print i1 =, i1.err_range(),: i2 =, i2.err_range() i1 = Value: 16, 31): i2 = Value: 16, 31) i3 = i1 + i2 print i3, type(i3) 47 由于新式类型int已经支持位操作,因

38、此没有必要专门再实现。用新式类型,你可以直接用self引用数据,而不需要一个专门的属性去保存数据(例如,I里的self.i)。同时,人们普遍会使用不安全的操作方式来实现一些神奇函数,例如,I里._add_()的函数就不如I2._add_()的方法。在实践中,你可能不会模仿数字类型。但它值得去理解是如何实现的。要完整的模仿int或long是非常困难的,不过有些功能是很值得利用的。主题 - 基础数据类自定义数据类型经常会定义一些常用的魔术性函数。事实上,使用这些方法甚至不需要专门的定义一个数据类型(某种意义上说,每一个对象都是一种数据类型,因为它可以包含属性值,但不是每个对象都支持特殊语法,如运算

39、符和索引)。本书不会详细介绍每一种专用函数,大多数魔术性函数都是跟继承的数据类型有关。此外,每个新版本的Python都会增加一些额外的魔术性功能,尤其最近几个版本更为明显。在定义类的时候,一般会使用相同的书写方式来定义。一个特别的公约就是这些类的函数都使用self作为第一个参数。self可以是任意其他名词,而且有几种不同的使用方式。例如,以下的例子中self具有和函数定义里同样的作用: import string self = spam object._repr_(self) string.upper(self) SPAM但是,通常是不会这样使用的。通常情况下,这种使用方法只会出现在子类定义中

40、需要覆盖父类的时候,如: class UpperObject(object): . def _repr_(self): . return object._repr_(self).upper() . uo = UpperObject() print uo BUILTIN - 对象: 新式数据类型原型在Python2.2+,object已经是新式数据类型了。从object继承的自定义类可以使用一些新的功能,如位置和属性。不过如果您有兴趣创建自定义数据类型,最好是继承object的子类,如list,float或dict.方法: object._eq_(self, other)返回self和other

41、比较的布尔值。这个决定了数据类型如何回应=运算。object类并没有具体实现._eq_()函数,默认情况下,对象相等意味着是同一个东西(is运算)。子类可以随意定义比较的方式。 object._ne_(self, other)返回self和other比较的布尔值。这个决定了数据类型如何回应!=和运算。object类没有具体实现._ne_()函数,默认情况下,对象不相等意味着不是同一个东西(is not运算)。似乎相等和不相等应该返回相反的值,但这并没有明确的限定。你可以强制这种关系: class EQ(object): . # 使用基础类的比较方式 . def _eq_(self, o): r

42、eturn not self o . def _ne_(self, o): return not self = o . class Comparable(EQ): . # 使用专门的比较方式 . def _ne_(self, other): . return someComplexComparison(self, other) object._nonzero_(self)返回一个布尔值,这决定了数据类型如何回应布尔运算or,and和not以及if和filter(None,.)测试。对象的._nonzero_()函数返回真值就视该对象为真。 object._len_(self) len(obje

43、ct)返回一个整数来代表对象的长度。对于容器型类型,这是很直接的意义-这个容器有多少个对象?自定义类型可能会有一些其他的意义。 object._repr_(self) repr(object) object._str_(self) str(object)返回一个字符串来表示self对象。这决定了数据类型如何响应repr()和str()内置函数,print会使用后者。尽可能让._repr_()返回足够的代表性信息,最好是能用它重建一个相同的对象。目的是要实现obj=eval(repr(obj)。但在许多情况下,你不可能在字符串里包含足够的信息编码。对象的repr()一般来说含带的信息要str()

44、详细。 SEE ALSO, repr, operatorBUILTIN - file: 文件对象的新式类在Python2.2+,可以通过继承内建类型file来创造自定义的文件对象。老版本你只能自己手工定义各种函数来创建file-like类型。不过即使使用最新版本的Python,你从file继承的文件类型如果使用的数据不是本地文件,那你还是要重新定义一些支持函数的。对比其他对象类,file-like是一种比较模糊的概念。根据你的需要这个对象可能只能读,或者是只能写。你可能还需要这个对象可以定位,或者还要有数据流特性。总的来说,file-like对象是用来读取和写入字符串。自定义类型只需要实现那些

45、需要实现的功能就足够了。在书写file-like对象的函数时,我会用和其他内置类型稍微不同的方式来写。事实上直接继承file是很少见的,我用大写名称FILE来表明一般的文件对象,只是把file作为参考的例子(实现所有已命名的函数功能)。内置函数: open(fname ,mode ,buffering) file(fname ,mode ,buffering)返回文件对象挂接fname。可选参数mode说明了访问对象的权限和能力。r模式是阅读,w是写(覆盖现有内容),a是附加(写在后面)。所有这些模式都可以附加一个b用于不同的平台,如区分Windows的文本和二进制文件。+是允许读和写。参数buffering可以是0空模式,1行模式,大数字表示字节数。 open(tmp,w).write(spam and eggsn) print open(tmp,r).read(), spam and eggs open(tmp,w).write(this and thatn) print open(tmp,r).read(), this and that open(tmp,a).write

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论