python

正则表达式,又称规则表达式(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。

许多程序设计语言都支持利用正则表达式进行字符串操作。例如,在Perl中就内建了一个功能强大的正则表达式引擎。正则表达式这个概念最初是由Unix中的工具软件(例如sed和grep)普及开的。正则表达式通常缩写成“regex”,单数有regexp、regex,复数有regexps、regexes、regexen。

正则引擎主要可以分为两大类:一种是DFA,一种是NFA。这两种引擎都有了很久的历史(至今二十多年),当中也由这两种引擎产生了很多变体!于是POSIX的出台规避了不必要变体的继续产生。这样一来,主流的正则引擎又分为3类:一、DFA,二、传统型NFA,三、POSIX NFA。

DFA引擎在线性时状态下执行,因为它们不要求回溯(并因此它们永远不测试相同的字符两次)。DFA 引擎还可以确保匹配最长的可能的字符串。但是,因为 DFA 引擎只包含有限的状态,所以它不能匹配具有反向引用的模式;并且因为它不构造显示扩展,所以它不可以捕获子表达式。

传统的 NFA 引擎运行所谓的“贪婪的”匹配回溯算法,以指定顺序测试正则表达式的所有可能的扩展并接受第一个匹配项。因为传统的 NFA 构造正则表达式的特定扩展以获得成功的匹配,所以它可以捕获子表达式匹配和匹配的反向引用。但是,因为传统的 NFA 回溯,所以它可以访问完全相同的状态多次(如果通过不同的路径到达该状态)。因此,在最坏情况下,它的执行速度可能非常慢。因为传统的 NFA 接受它找到的第一个匹配,所以它还可能会导致其他(可能更长)匹配未被发现。

POSIX NFA 引擎与传统的 NFA 引擎类似,不同的一点在于:在它们可以确保已找到了可能的最长的匹配之前,它们将继续回溯。因此,POSIX NFA 引擎的速度慢于传统的 NFA 引擎;并且在使用 POSIX NFA 时,您恐怕不会愿意在更改回溯搜索的顺序的情况下来支持较短的匹配搜索,而非较长的匹配搜索。

使用DFA引擎的程序主要有:awk,egrep,flex,lex,MySQL,Procmail等;

使用传统型NFA引擎的程序主要有:GNU Emacs,Java,ergp,less,more,.NET语言,PCRE library,Perl,PHP,Python,Ruby,sed,vi;

使用POSIX NFA引擎的程序主要有:mawk,Mortice Kern Systems’ utilities,GNU Emacs(使用时可以明确指定);

也有使用DFA/NFA混合的引擎:GNU awk,GNU grep/egrep,Tcl。

举例简单说明NFA与DFA工作的区别:

比如有字符串this is yansen’s blog,正则表达式为 /ya(msen|nsen|nsem)/ (不要在乎表达式怎么样,这里只是为了说明引擎间的工作区别)。 NFA工作方式如下,先在字符串中查找 y 然后匹配其后是否为 a ,如果是 a 则继续,查找其后是否为 m 如果不是则匹配其后是否为 n (此时淘汰msen选择支)。然后继续看其后是否依次为 s,e,接着测试是否为 n ,是 n 则匹配成功,不是则测试是否为 m 。为什么是 m ?因为 NFA 工作方式是以正则表达式为标准,反复测试字符串,这样同样一个字符串有可能被反复测试了很多次!

而DFA则不是如此,DFA会从 this 中 t 开始依次查找 y,定位到 y ,已知其后为a,则查看表达式是否有 a ,此处正好有a 。然后字符串a 后为n ,DFA依次测试表达式,此时 msen 不符合要求淘汰。nsen 和 nsem 符合要求,然后DFA依次检查字符串,检测到sen 中的 n 时只有nsen 分支符合,则匹配成功!

由此可以看出来,两种引擎的工作方式完全不同,一个(NFA)以表达式为主导,一个(DFA)以文本为主导!一般而论,DFA引擎则搜索更快一些!但是NFA以表达式为主导,反而更容易操纵,因此一般程序员更偏爱NFA引擎! 两种引擎各有所长,而真正的引用则取决与你的需要以及所使用的语言。

文件内建函数[open()和 file()]

1open('filename')2with open('filename')as f:3pass

open函数使用一个文件名作为唯一的强制参数,然后返回一个文件对象。模式和缓冲参数都是可选的,默认为只读模式打开文件。使用with即使发生错误可以关闭文件,

下面列出文件对象的访问的模式:

1文件模式   操作 2r  以只读方式打开 3rU 或 Ua 以读方式打开, 同时提供通用换行符支持 (PEP 278) 4w  以写方式打开 (必要时清空) 5a  以追加模式打开 (从 EOF 开始, 必要时创建新文件) 6r+ 以读写模式打开 7w+ 以读写模式打开 (参见 w ) 8a+ 以读写模式打开 (参见 a ) 9rb 以二进制读模式打开10wb 以二进制写模式打开 (参见 w )11ab 以二进制追加模式打开 (参见 a )12rb+ 以二进制读写模式打开 (参见 r+ )13wb+ 以二进制读写模式打开 (参见 w+ )14ab+ 以二进制读写模式打开 (参见 a+ )15x    如果文件存在报错,不存在则创建16***加b模式打开,不可以在指定encoding,切写入时也需要转换为字节写入文件1718下面是一些打开文件的例子:19f = open('/etc/motd')# 以读方式打开20f = open('test','w')# 以写方式打开21f = open('data','r+')# 以读写方式打开22f = open('io.sys','rb')# 以二进制读模式打开2324bytes 字符串转换字节类型25n=bytes(李杰,encoding='utf-8')[转换的字符,可以是变量,转换后的编码]26字节转换为字符串27str(bytes(李杰,encoding='utf-8'),encoding='utf-8)28文件操作

open() 和 file() 函数具有相同的功能, 可以任意替换.任何使用 open() 的地方, 都可以使用 file() 替换它.建议使用 open() 来读写文件, 在处理文件对象时使用 file() 。open() 成功执行并返回一个文件对象之后, 所有对该文件的后续操作都将通过这个"句柄"进行.

Version:1.0StartHTML:000000297EndHTML:000036391StartFragment:000027091EndFragment:000036317StartSelection:000027094EndSelection:000036313SourceURL:https://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/0013868200196665403ac40fac14536939dd5af20810782000

ython本身就内置了很多非常有用的模块,只要安装完毕,这些模块就可以立刻使用。

我们以内建的sys模块为例,编写一个hello的模块:

#!/usr/bin/env python# -*- coding: utf-8 -*-' a test module '__author__ ='Michael Liao'importsysdeftest():args = sys.argviflen(args)==1:print'Hello, world!'eliflen(args)==2:print'Hello, %s!'% args[1]else:print'Too many arguments!'if__name__=='__main__':    test()

第1行和第2行是标准注释,第1行注释可以让这个hello.py文件直接在Unix/Linux/Mac上运行,第2行注释表示.py文件本身使用标准UTF-8编码;

第4行是一个字符串,表示模块的文档注释,任何模块代码的第一个字符串都被视为模块的文档注释;

第6行使用__author__变量把作者写进去,这样当你公开源代码后别人就可以瞻仰你的大名;

以上就是Python模块的标准文件模板,当然也可以全部删掉不写,但是,按标准办事肯定没错。

后面开始就是真正的代码部分。

你可能注意到了,使用sys模块的第一步,就是导入该模块:

importsys

导入sys模块后,我们就有了变量sys指向该模块,利用sys这个变量,就可以访问sys模块的所有功能。

sys模块有一个argv变量,用list存储了命令行的所有参数。argv至少有一个元素,因为第一个参数永远是该.py文件的名称,例如:

运行python hello.py获得的sys.argv就是['hello.py'];

运行python hello.py Michael获得的sys.argv就是['hello.py', 'Michael]。

最后,注意到这两行代码:

if__name__=='__main__':test()

当我们在命令行运行hello模块文件时,Python解释器把一个特殊变量__name__置为__main__,而如果在其他地方导入该hello模块时,if判断将失败,因此,这种if测试可以让一个模块通过命令行运行时执行一些额外的代码,最常见的就是运行测试。

我们可以用命令行运行hello.py看看效果:

$ python hello.pyHello, world!$ python hello.pyMichaelHello,Michael!

如果启动Python交互环境,再导入hello模块:

$ pythonPython2.7.5(default, Aug252013,00:04:04) [GCC4.2.1Compatible Apple LLVM5.0(clang-500.0.68)] on darwinType"help","copyright","credits"or"license"formore information.>>> importhello>>>

导入时,没有打印Hello, word!,因为没有执行test()函数。

调用hello.test()时,才能打印出Hello, word!:

>>> hello.test()Hello, world!

别名

导入模块时,还可以使用别名,这样,可以在运行时根据当前环境选择最合适的模块。比如Python标准库一般会提供StringIO和cStringIO两个库,这两个库的接口和功能是一样的,但是cStringIO是C写的,速度更快,所以,你会经常看到这样的写法:

try:importcStringIOasStringIOexceptImportError:# 导入失败会捕获到ImportErrorimportStringIO

这样就可以优先导入cStringIO。如果有些平台不提供cStringIO,还可以降级使用StringIO。导入cStringIO时,用import ... as ...指定了别名StringIO,因此,后续代码引用StringIO即可正常工作。

还有类似simplejson这样的库,在Python 2.6之前是独立的第三方库,从2.6开始内置,所以,会有这样的写法:

try:importjson# python >= 2.6exceptImportError:importsimplejsonasjson# python <= 2.5

由于Python是动态语言,函数签名一致接口就一样,因此,无论导入哪个模块后续代码都能正常工作。

作用域

在一个模块中,我们可能会定义很多函数和变量,但有的函数和变量我们希望给别人使用,有的函数和变量我们希望仅仅在模块内部使用。在Python中,是通过_前缀来实现的。

正常的函数和变量名是公开的(public),可以被直接引用,比如:abc,x123,PI等;

类似__xxx__这样的变量是特殊变量,可以被直接引用,但是有特殊用途,比如上面的__author__,__name__就是特殊变量,hello模块定义的文档注释也可以用特殊变量__doc__访问,我们自己的变量一般不要用这种变量名;

类似_xxx和__xxx这样的函数或变量就是非公开的(private),不应该被直接引用,比如_abc,__abc等;

之所以我们说,private函数和变量“不应该”被直接引用,而不是“不能”被直接引用,是因为Python并没有一种方法可以完全限制访问private函数或变量,但是,从编程习惯上不应该引用private函数或变量。

private函数或变量不应该被别人引用,那它们有什么用呢?请看例子:

def_private_1(name):return'Hello, %s'% namedef_private_2(name):return'Hi, %s'% namedefgreeting(name):iflen(name) >3:return_private_1(name)else:return_private_2(name)

我们在模块里公开greeting()函数,而把内部逻辑用private函数隐藏起来了,这样,调用greeting()函数不用关心内部的private函数细节,这也是一种非常有用的代码封装和抽象的方法,即:

外部不需要引用的函数全部定义成private,只有外部需要引用的函数才定义为public。

作业:

你可能感兴趣的:(python)