python之路[3] - 正则表达式和函数基础 - 迁

正则表达式

text = "JGood is a handsome boy, he is cool, clever, and so on..."

re.compile(pattern,flags=0)      -- 设置匹配规则  
re.match(pattern,string, flags=0) -- 字符串的开头是否能匹配正则表达式
re.search(pattern,string, flags=0) -- 在字符串中查找,是否能匹配正则表达式
re.findall(pattern,string[,flags]) -- 返回匹配的所有子串,并把它们作为一个列表返回。这个匹配是从左到右有序地返回,它是没有group()的

re.splitall()    --      以匹配到的字符当做列表分隔符

re.sub(pattern,)        --    匹配字符并替换

 

下面我们一起看下他们的用法

re.findall('\w+oo\w+',text)   
[
'JGood', 'cool'] ​

re.match('(a(b))', 'ab').groups()
('ab', 'b')

mo=re.compile(r'(?<=SRC=)"([\W+\.]+)"',re.I)
>> mo.sub(r'"\1*****"', line) # 把匹配到字符串后面加××××× ,\1是匹配到的数据

 

常用正则表达式

'.'     默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行
'^'     匹配字符开头,若指定flags MULTILINE,这种也可以匹配上(r"^a","\nabc\neee",flags=re.MULTILINE)
'$'     匹配字符结尾,或e.search("foo$","bfoo\nsdfsf",flags=re.MULTILINE).group()也可以
'*'     匹配*号前的字符0次或多次,re.findall("ab*","cabb3abcbbac")  结果为['abb', 'ab', 'a']
'+'     匹配前一个字符1次或多次,re.findall("ab+","ab+cd+abb+bba") 结果['ab', 'abb']
'?'     匹配前一个字符1次或0次
'{m}'   匹配前一个字符m次
'{n,m}' 匹配前一个字符n到m次,re.findall("ab{1,3}","abb abc abbcbbb") 结果'abb', 'ab', 'abb']
'|'     匹配|左或|右的字符,re.search("abc|ABC","ABCBabcCD").group() 结果'ABC'
'(...)' 分组匹配,re.search("(abc){2}a(123|456)c", "abcabca456c").group() 结果 abcabca456c
 
'\A'    只从字符开头匹配,re.search("\Aabc","alexabc") 是匹配不到的
'\Z'    匹配字符结尾,同$
'\d'    匹配数字0-9
'\D'    匹配非数字
'\w'    匹配[A-Za-z0-9]
'\W'    匹配非[A-Za-z0-9]
's'     匹配空白字符、\t、\n、\r , re.search("\s+","ab\tc1\n3").group() 结果 '\t'

# 匹配所有汉字
print(re.findall('[\u4e00-\u9fa5]', data))

# 匹配所有单字符,英文,数字,特殊符号
print(re.findall('[\x00-\xff]', data))

# 匹配所有非单字符,入汉字和省略号
print(re.findall('[^\x00-\xff]', data))

'(?P<name>...)' 分组匹配 
re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<birthday>[0-9]{4})","371481199306143242").groupdict() 
结果{'province': '3714', 'city': '81', 'birthday': '1993'}

  

  

 

转义

反斜杠的困扰
与大多数编程语言相同,正则表达式里使用"\"作为转义字符,这就可能造成反斜杠困扰。假如你需要匹配文本中的字符"\",那么使用编程语言表示的正则表达式里将需要4个反斜杠"\\\\":前两个和后两个分别用于在编程语言里转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。Python里的原生字符串很好地解决了这个问题,这个例子中的正则表达式可以使用r"\\"表示。同样,匹配一个数字的"\\d"可以写成r"\d"。有了原生字符串,你再也不用担心是不是漏写了反斜杠,写出来的表达式也更直观。

  

匹配模式

re.I(re.IGNORECASE): 忽略大小写(括号内是完整写法,下同)
M(MULTILINE): 多行模式,改变'^''$'的行为(参见上图)
S(DOTALL): 点任意匹配模式,改变'.'的行为

 

贪婪匹配

.+(\d+-\d+-\d+)
.+ 是贪婪匹配,会将 dfd:1171590364-6-8 匹配成 4-6-8

这时候利用? 非贪婪操作符 .+?(\d+-\d+-\d+) 就能匹配成1171590364-6-8

  

场合应用

1 密码的强度必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间
^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$

2 字符串只能是中文
^[\\u4e00-\\u9fa5]{0,}$

3 校验E-Mail 地址
[\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[\\w](?:[\\w-]*[\\w])?

4 校验身份证号码
15位:
^[1-9]\\d{7}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}$
18位:
^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([0-9]|X)$

5 校验日期
“yyyy-mm-dd“ 格式的日期校验,已考虑平闰年
^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$

6 校验金额
金额校验,精确到2位小数
^[0-9]+(.[0-9]{2})?$

7 校验手机号
下面是国内 13、15、18开头的手机号正则表达式
^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\\d{8}$

8 判断IE的版本
^.*MSIE [5-8](?:\\.[0-9]+)?(?!.*Trident\\/[5-9]\\.0).*$

9 校验IP-v4地址
\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b

10 匹配01- 12月
re.match('(0[1-9])?(1[1-2])?',s).group() 
View Code

 

函数

定义

函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可

特性:

  1. 减少重复代码
  2. 使程序变的可扩展
  3. 使程序变得易维护

函数参数与局部变量

关键参数

正常情况下,给函数传参数要按顺序,不想按顺序就可以用关键参数,只需指定参数名即可,但记住一个要求就是,关键参数必须放在位置参数之后。

def stu_register(name,age,course,country="CN"):

def stu_register(age=22,name='alex',course="python",)

 

 

非固定参数

def stu_register(name,age,*args,**kwargs): # *kwargs 会把多传入的参数变成一个dict形式
    print(name,age,args,kwargs)
 
stu_register("Alex",22)
#输出
#Alex 22 () {}#后面这个{}就是kwargs,只是因为没传值,所以为空
 
stu_register("Jack",32,"CN","Python",sex="Male",province="ShanDong")
#输出
# Jack 32 ('CN', 'Python') {'province': 'ShanDong', 'sex': 'Male'}

 

 

全局与局部变量

在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。
name = "gaotao"  #全局变量

def change_name(name):
    global car
    car = "ford" # 全局变量
    print("before change:",name)
    name = "帅帅"   # 局部变量
    print("after change", name)
 
change_name(name)
print(car)

 

 

嵌套函数

name = "gaotao"
 
def change_name():
    name = "gaotao2"
 
    def change_name2():
        name = "gaotao3"
        print("3",name)
 
    change_name2() #调用内层函数
    print("2",name)
 
 
change_name()
print("outhear",name)

 

输出:

('3', 'gaotao3')
('2', 'gaotao2')
('outhear', 'gaotao')

 

递归

在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。

def calc(n):
    print(n)
    if int(n/2) ==0:
        return n
    return calc(int(n/2))
 
calc(10)
 
输出:
10
5
2
1

 

递归特性:

1. 必须有一个明确的结束条件

2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少

3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)

堆栈扫盲http://www.cnblogs.com/lln7777/archive/2012/03/14/2396164.html 

 

data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35]
 
 
def binary_search(dataset,find_num):
    print(dataset)
 
    if len(dataset) >1:
        mid = int(len(dataset)/2)
        if dataset[mid] == find_num:  #find it
            print("找到数字",dataset[mid])
        elif dataset[mid] > find_num :# 找的数在mid左面
            print("\033[31;1m找的数在mid[%s]左面\033[0m" % dataset[mid])
            return binary_search(dataset[0:mid], find_num)
        else:# 找的数在mid右面
            print("\033[32;1m找的数在mid[%s]右面\033[0m" % dataset[mid])
            return binary_search(dataset[mid+1:],find_num)
    else:
        if dataset[0] == find_num:  #find it
            print("找到数字啦",dataset[0])
        else:
            print("没的分了,要找的数字[%s]不在列表里" % find_num)
 
 
binary_search(data,66)
递归函数实际应用案例,二分查找

 

利用递归将 字典扁平化

REST=[]
def dict2kv(vdict,str_key="",split_pot=":",startwith=None): 
    if isinstance(vdict,(dict,)):
        for k,v in vdict.items():
            tmp_key = str_key+split_pot+k
            dict2kv(vdict=vdict[k],str_key=tmp_key,split_pot=split_pot,startwith=startwith)
    else:
        _key = "%s%s" % (startwith,str_key)
        REST.append({_key:vdict})
        str_key = ""
        return 0

注意REST是全局变量,如果重复调用dict2kv,需要每次循环前置空  

  

调用结果

vdict = {
    'nihao':{
        '1':'sdf',
        '2ss':'w3d'
    },
    'ch':{
        'hhe':{
            'zen':'33'
        }
    }
}


dict2kv(vdict,startwith="DATASOURCE_STATUS")

>> [{'DATASOURCE_STATUS:ch:hhe:zen': '33'},
 {'DATASOURCE_STATUS:nihao:1': 'sdf'},
 {'DATASOURCE_STATUS:nihao:2ss': 'w3d'}]

  

  

 

os.walk 模块就是很好的递归函数事例

def walk(top, topdown=True, onerror=None, followlinks=False):

    islink, join, isdir = path.islink, path.join, path.isdir
    try:
        # Note that listdir and error are globals in this module due
        # to earlier import-*.
        names = listdir(top)
    except error, err:
        if onerror is not None:
            onerror(err)
        return

    dirs, nondirs = [], []
    for name in names:
        if isdir(join(top, name)):
            dirs.append(name)
        else:
            nondirs.append(name)

    if topdown:
        yield top, dirs, nondirs
    for name in dirs:
        new_path = join(top, name)
        if followlinks or not islink(new_path):
            for x in walk(new_path, topdown, onerror, followlinks):
                yield x
    if not topdown:
        yield top, dirs, nondirs

  

  

 

内置参数

内置参数详解 https://docs.python.org/3/library/functions.html?highlight=built#ascii 

 

posted @ 2017-11-06 18:12  richardzgt  阅读(262)  评论(0编辑  收藏  举报