正则表达式与re模块
正则表达式
正则表达式是对字符串操作的一种逻辑公式.我们一般使用正则表达式对字符串进行匹配和过滤.
使用正则的优缺点:
优点: 灵活, 功能性强, 逻辑性强.
缺点: 上手难. 一旦上手, 会爱上这个东西
元字符
'.' 默认匹配除\n之外的任意一个字符,若指定flag DOTALL, 则匹配任意字符,包括换行
'^' 匹配字符开头,若指定flags MULTILINE, 这种也可以匹配上(r"^a", "\nabc\neee", flags=re.MULTILINE)
'$' 匹配字符结尾,或e.search("foo$", "bfoo\nsdfsf", flags=re.MULTILINE).group()也可以
'|' 匹配 | 左或 | 右的字符,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'' \
量词
'*' 匹配 * 号前的字符0次或多次,
'+' 匹配前一个字符1次或多次,
'?' 匹配前一个字符1次或0次,尽可能的少
'{m}' 匹配前一个字符m次
'{n,m}' 匹配前一个字符n到m次,
转义
在正则:
\.
\元字符
python
"\\."
r"\."
惰性匹配
* + {} 都是贪婪匹配,尽可能多的匹配到结果
.? +? {}? ,惰性匹配,尽可能少的匹配
量词后面加问号
.*?abc 一直取遇到abc就停
分组
() 优先级最高
/1 再次匹配第一个分组
1 import re 2 3 # 常用语法: 4 # re.findall 把所有匹配到的字符放到以列表中的元素返回 5 # re.finditer() # 与findall相同,返回的是迭代器 6 # re.search 会进行匹配. 但是如果匹配到了第一个结果. 就会返回这个结果. 如果匹配不上search返回的则是None 7 # re.match 从头开始匹配 8 # re.splitall 以匹配到的字符当做列表分隔符 9 # re.sub 匹配字符并替换 10 # compile 编译 :正则表达式很长且要多次使用 11 12 13 # ret = re.findall('[a-z]+', 'eva egon yuan') 14 # 返回所有满足匹配条件的结果,放在列表里 15 # print(ret) # ['eva', 'egon', 'yuan'] 16 17 # ret = re.search('a', 'eva egon yuan') 18 # if ret: 19 # print(ret.group()) 20 # # 从前往后,找到一个就返回,返回的变量需要调用group才能拿到结果 21 # # 如果没有找到,那么返回None,调用group会报错 22 23 # ret = re.match('[a-z]+', 'eva egon yuan') 24 # if ret: 25 # print(ret.group()) 26 # match是从头开始匹配,如果正则规则从头开始可以匹配上,就返回一个变量。 27 # 匹配的内容需要用group才能显示 28 # 如果没匹配上,就返回None,调用group会报错 29 30 # ret = re.split('[ab]', 'abcd') 31 # # # 先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割 32 # print(ret) # ['', '', 'cd'] 33 34 # ret = re.sub('\d', 'H', 'eva3egon4yuan4',1) 35 # 将数字替换成'H',参数1表示只替换1个 36 # print(ret) #evaHegon4yuan4 37 38 # ret = re.subn('\d', 'H', 'eva3egon4yuan4') 39 # #将数字替换成'H',返回元组(替换的结果,替换了多少次) 40 # print(ret) 41 42 # obj = re.compile('\d{3}') 43 # #将正则表达式编译成为一个正则表达式对象,规则要匹配的是3个数字 44 # ret = obj.search('abc123eeee') #正则表达式对象调用search,参数为待匹配的字符串 45 # print(ret.group()) 46 # ret = obj.search('abcashgjgsdghkash456eeee3wr2') #正则表达式对象调用search,参数为待匹配的字符串 47 # print(ret.group()) #结果 : 123 48 49 # ret = re.finditer('\d', 'ds3sy4784a') #finditer返回一个存放匹配结果的迭代器 50 # print(ret) # <callable_iterator object at 0x10195f940> 51 # for i in ret: 52 # print(i.group()) 53 54 # ------------------元字符-------------------------- 55 56 # '.' 默认匹配除\n之外的任意一个字符,若指定flag DOTALL, 则匹配任意字符,包括换行 57 # '^' 匹配字符开头,若指定flags MULTILINE, 这种也可以匹配上(r"^a", "\nabc\neee", flags=re.MULTILINE) 58 # '$' 匹配字符结尾,或e.search("foo$", "bfoo\nsdfsf", flags=re.MULTILINE).group()也可以 59 # '*' 匹配 * 号前的字符0次或多次,re.findall("ab*", "cabb3abcbbac")结果为['abb', 'ab', 'a'] 60 # '+' 匹配前一个字符1次或多次,re.findall("ab+", "ab+cd+abb+bba")结果['ab', 'abb'] 61 # '?' 匹配前一个字符1次或0次 62 # '{m}' 匹配前一个字符m次 63 # '{n,m}' 匹配前一个字符n到m次,re.findall("ab{1,3}", "abb abc abbcbbb")结果 'abb', 'ab', 'abb'] 64 # '|' 匹配 | 左或 | 右的字符,re.search("abc|ABC", "ABCBabcCD").group()结果 'ABC' 65 # '(...)' 分组匹配,re.search("(abc){2}a(123|456)c", "abcabca456c").group()结果abcabca456c 66 # 67 # '\A' 只从字符开头匹配,re.search("\Aabc", "alexabc")是匹配不到的 68 # '\Z' 匹配字符结尾,同$ 69 # '\d' 匹配数字0 - 9 70 # '\D' 匹配非数字 71 # '\w' 匹配[A - Za - z0 - 9] 72 # '\W' 匹配非[A - Za - z0 - 9] 73 # 's' 匹配空白字符、\t、\n、\r, re.search("\s+", "ab\tc1\n3").group()结果'\t'' \ 74 75 76 # 分组命名 77 # (?P<name>...) The substring matched by the group is accessible by name. 78 # obj = re.compile(r'(?P<id>\d+)(?P<name>e+)') # 从正则表达式匹配的内容每个组起名字 79 # ret = obj.search('abc123eeee') # 搜索 80 # print(ret.group()) # 结果: 123eeee 81 # print(ret.group("id")) # 结果: 123 # 获取id组的内容 82 # print(ret.group("name")) # 结果: eeee # 获取name组的内容 83 # (...)与(?:...) 84 # () 获取匹配的结果 85 # (?:...) 不获取匹配的结果 86 # findall 87 # ret = re.findall('www.(baidu|oldboy).com', 'www.oldboy.com') 88 # print(ret) # ['oldboy'] 89 # ret = re.findall('www.(?:baidu|oldboy).com', 'www.oldboy.com') 90 # print(ret) # ['www.oldboy.com' 91 # split 92 # ret=re.split("\d+","eva3egon4yuan") 93 # print(ret) #结果 : ['eva', 'egon', 'yuan'] 94 # ret=re.split("(\d+)","eva3egon4yuan") 95 # print(ret) #结果 : ['eva', '3', 'egon', '4', 'yuan'] 96 # # 在匹配部分加上()之后所切出的结果是不同的, 97 # # 没有()的没有保留所匹配的项,但是有()的却能够保留留了匹配的项, 98 # # 这个在某些需要保留匹配部分的使用过程是非常重要的。 99 100 # 其他(没做深入了解) 101 # (?=...) Matches if ... matches next, but doesn't consume the string. 102 # (?!...) Matches if ... doesn't match next. 103 # (?<=...) Matches if preceded by ... (must be fixed length). 104 # (?<!...) Matches if not preceded by ... (must be fixed length). 105 106 # -----------------------常见问题---------------------------------- 107 # 转义的问题 108 # import re 109 # re.findall(r'\\s',r'\s') 110 111 # 惰性匹配 112 # 量词后面加问号 113 # .*?abc 一直取遇到abc就停
1 import re 2 3 4 def add_sub(equation): 5 """ 6 计算加减算式,并返回结果 7 :param equation: 1+2,1-1 8 :return: float 9 """ 10 # 这里用eval代替了计算加减的函数 11 return eval(equation) 12 13 14 def mul_div(equation): 15 """ 16 计算加减乘除算式,返回结果。 两端带有括号,里面没有括号 17 :param equation: 包含有加减乘除的式子 18 :return: float 19 """ 20 # (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 ) 21 equation = equation.strip('()') 22 equation = equation.replace('++', '+') 23 equation = equation.replace('+-', '-') 24 equation = equation.replace('-+', '-') 25 equation = equation.replace('--', '+') 26 while True: 27 if '*' in equation or '/' in equation: 28 old = re.search('[\d.]*[*/][-]?[\d.]*', equation) 29 equation = equation.replace(old.group(), str(eval(old.group()))) 30 # 这里eval代替了计算乘除的函数,1*2,1/2,1*-1 31 else: 32 return add_sub(equation) 33 34 35 def analyze_cal(equation): 36 while True: 37 if '(' in equation: 38 old = re.search('\([^()]*\)', equation) 39 equation = equation.replace(old.group(), str(mul_div(old.group()))) 40 else: 41 return mul_div(equation) 42 43 44 if __name__ == '__main__': 45 a = '1 - 2 * ( ( 6 0 -3 0 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )' 46 a = a.replace(' ', '') 47 print(analyze_cal(a))