Re模块:(正则表达式)
正则表达式就是字符串的匹配规则
正则表达式在多数编程语言里都有相应的支持,Python里面对应的模块时re
常用的表达式规则:(都需要记住)
“ . ” # 默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行
“ ^ ” # 匹配字符开头,
若指定flags MULTILINE,这种也可以匹配上("^a","\nabc\neee",flags=re.MULTILINE)(即:如果flags指定了 re.MULTILINE, 每一行都会尝试去匹配)
“ $ ” # 匹配字符结尾,若指定flags MULTILINE ,re.search(‘foo.$‘,‘foo1\nfoo2\n‘,re.MULTILINE).group() 会匹配到foo1。 (如果flags指定了 re.MULTILINE, 每一行都会尝试去匹配)
“ * ” # 匹配*号前的字符0次或多次, re.search(‘a*‘,‘aaaabac‘) 结果‘aaaa‘; # ab* will match ‘a’, ‘ab’, or ‘a’ followed by any number of ‘b’s.
“ + ” # 匹配“+”前一个字符1次或多次,re.findall("ab+","ab+cd+abb+bba") 结果[‘ab‘, ‘abb‘] # ab+
will match ‘a’ followed by any non-zero number of ‘b’s; it will not match just ‘a’.
“ ? ” # 匹配“?”前一个字符1次或0次 ,re.search(‘b?‘,‘alex‘).group() 匹配b 0次 # ab?
will match either ‘a’ or ‘ab’.
“ {m} ” # 匹配前一个字符m次 ,re.search(‘b{3}‘,‘alexbbbs‘).group() 匹配到‘bbb‘
“ {n,m} ” # 匹配前一个字符n到m次,re.findall("ab{1,3}","abb abc abbcbbb") 结果[‘abb‘, ‘ab‘, ‘abb‘]
“ [ ] ” # Used to indicate a set of characters. 在[ ] 中的字符, 可以单独列出来(如:[abc123]),也可以用“-”表示一个范围(如:[0-9])
“ | ” # 匹配|左或|右的字符,re.search("abc|ABC","ABCBabcCD").group() 结果‘ABC‘
“ ( ... ) ” # 分组匹配; 利用 .groups() 查看分开后的匹配结果(元祖形式)(涉及到分组就用. groups())
注:以上的全部都经常使用
“ \A ” # 只从字符开头匹配,re.search("\Aabc","alexabc") 是匹配不到的,相当于re.match(‘abc‘,"alexabc") 或re.search(‘^abc‘, ‘xxx‘)
“ \Z ” # 匹配字符结尾, 同$
“ \d ” # 匹配数字0到9, 相当于[0-9](经常使用) # re.search(‘\d+‘, string) # 贪婪匹配模式
“ \D ” # 匹配非数字 (经常使用)
“ \w ” # 匹配[A-Za-z0-9] (即非特殊字符) (经常使用)
“ \W ” # 匹配非[A-Za-z0-9] (即特殊字符) (经常使用)
“ \s ” # 匹配空白字符、\n、\t、\r ;
“ (?P<name>...) ” # 分组匹配 ; 举例如下:
import re id_s = ‘130704200005251653‘ res = re.search(‘(?P<province>\d{3})(?P<city>\d{3})(?P<born_year>\d{4})‘,id_s) print(res.group()) print(res.groups()) # 涉及到分组就用 groups # 以字典的形式输出 print(res.groupdict()) # 打印结果: # 1307042000 # (‘130‘, ‘704‘, ‘2000‘) # {‘province‘: ‘130‘, ‘city‘: ‘704‘, ‘born_year‘: ‘2000‘}
re的匹配语法有以下几种:
- re.match(pattern,string,flags=0) # 从头开始匹配;检测字符串的第一个元素是否匹配你所设置的pattern,后面的元素不再检测是否匹配,并返回匹配到的元素或者“None” # 官方解释:
If zero or more characters at the beginning of string match the regular expression pattern, return a corresponding match object. Return
None
if the string does not match the pattern; note that this is different from a zero-length match.Note that even in
MULTILINE
mode,re.match()
will only match at the beginning of the string and not at the beginning of each line.If you want to locate a match anywhere in string, use
search()
instead - re.search(pattern,string,flags=0) # 遍历整个字符串找到第一个匹配你pattern的元素,后面的元素不再检测是否匹配,并返回匹配到的元素或者“None” # 官方解释: Scan through string looking for the first location where the regular expression pattern produces a match, and return a corresponding match object. Return
None
if no position in the string matches the pattern; note that this is different from finding a zero-length match at some point in the string. - re.findall(pattern, string,flags=0) # 把所有匹配到的字符(元素)放到以列表中的元素返回 # 官方解释: Return all non-overlapping matches of pattern in string, as a list of strings. The string is scanned left-to-right(从左向右扫描字符串匹配), and matches are returned in the order found. If one or more groups are present in the pattern, return a list of groups; this will be a list of tuples if the pattern has more than one group. Empty matches are included in the result.
下面看下re.match()和 re.search()的运行效果:
import re s = ‘1ab2c3‘ print(re.search(‘[0-9]‘,s)) print(re.match(‘[0-9]‘,s)) # 打印结果: # <_sre.SRE_Match object; span=(0, 1), match=‘1‘> # <_sre.SRE_Match object; span=(0, 1), match=‘1‘> # search 和match返回的是一个对象, 不是匹配到的值。 # 要得到匹配到的值,可以利用 .group(),但需要先判断是否存在,因为如果没有匹配到就用.group()程序会报错 res_match = re.search(‘[0-9]‘,s) if res_match: # 先进行判断 print(res_match.group()) # 打印结果: # 1
- re,split(pattern, string, maxsplit=0,flags=0) # 以匹配到的字符作为分隔符(正则表达式可以用来做模糊规则)
情况1: import re s = ‘neo22alex18#mike-oldboy‘ print(re.split(‘\d+|#|-‘,s)) # pattern:按照 \d+ 或者“#” 或者 - 去split # 输出结果: # [‘neo‘, ‘alex‘, ‘‘, ‘mike‘, ‘oldboy‘] # 第3个空元素是因为18split之后 “#”也split, 成了空元素
# 上面是利用管道符“|”去定义pattern,下面利用[]去定义
import re
s = ‘neo22alex18#mike-oldboy‘
print(re.split(‘[\d+#-]‘,s)) # []就表示里面的都包括,效果就跟“|”类似,但有区别(代码中要注意[]和|具体用哪种), 这个例子只是想强调“[]就表示里面的都包括”这个知识点
# 输出结果:
# [‘neo‘, ‘‘, ‘alex‘, ‘‘, ‘‘, ‘mike‘, ‘oldboy‘] # \d+没有当做一个整体去split,而是分成了\d和字符“+”去split, 我也还没想清楚为什么。。。
情况2:
import re
s = ‘neo22alex18|mike-oldboy‘ # 假如要求以“|”为分隔符
print(re.split(‘\|‘,s)) # | 也是一个语法, 假如你在pattern不想让它作为语法、而是作为字符来使用, 就在它前面加一个斜杠“\”
# 输出结果:
# [‘neo22alex18‘, ‘mike-oldboy‘]
# 如果想把斜杠“\”当做字符而不是语法来使用, 就在这个“\”后面再加3个“\”, 即总共4个“\” (不理解原因,先记住吧)
import re
s = ‘neo22alex18\mike-oldboy‘
print(re.split(‘\\\\‘,s))
# 输出结果:
# [‘neo22alex18‘, ‘mike-oldboy‘]
- re.sub(pattern, repl, string, count=0,flags=0) # 匹配字符并替换
import re s = ‘neo22alex18\mike-oldboy‘ print(re.sub(‘\d+‘,‘+‘,s)) # 输出结果: # neo+alex+\mike-oldboy
- re.fullmatch(pattern, string,flags=0) # 全部匹配: 整个字符串匹配
re.fullmatch(‘\[email protected]\w+\.(com|cn|edu)‘,"[email protected]") # com|cn|edu 是一组的 , 需要放到一个括号里面
# 输出结果: # <_sre.SRE_Match object; span=(0, 17), match=‘[email protected]‘>
- re.compile(pattern, flags=0) # 用于编写一个匹配规则(pattern) # 如果你这个pattern要用很多次,可以利用compile先把pattern设置好, 以后直接调用就行; 不像 re.match(pattern, string) 这类的语句Python需要每次先对pattern编译,compile的pattern Python只需要编译一次以后直接调用就行。如下:
Compile a regular expression pattern into a regular expression object, which can be used for matching using its match(), search() and other methods, described below. The sequence prog = re.compile(pattern) result = prog.match(string) is equivalent to result = re.match(pattern, string) but using re.compile() and saving the resulting regular expression object for reuse is more efficient when the expression will be used several times in a single program.
Flag标识符:
- re.I(re.IGNORECASE): 忽略大小写(括号内是完整写法,下同)
- M(MULTILINE): 多行模式,改变‘^‘和‘$‘的行为
- S(DOTALL): 改变‘.‘的行为:make the ‘.‘ special character match any character at all, including a newline(换行); without this flag, ‘.‘ will match anything except a newline. (换行符也包括在内)
-
X(re.VERBOSE) 可以给你的表达式写注释,使其更可读,下面这2个意思一样
a = re.compile(r"""\d + # the integral part \. # the decimal point \d * # some fractional digits""", re.X) b = re.compile(r"\d+\.\d*")
软件开发目录规范:
规范化的目录结构能更好的控制程序就够,让程序具有更高的可读性。
“项目目录规范”其实也属于“可读性和可维护性”的范畴,设计层次清晰的目录结构就是为了达到以下两点:
1. 可读性高: 不熟悉这个项目代码的人,一眼就能就能看懂目录结构,知道程序启动脚本是哪个,测试目录在哪儿,配置文件在哪儿等等,从而非常快速的了解这个项目
2. 可维护性高: 定义好组织规则后,维护着就能明确的知道,新增的哪个文件和代码应该放在什么目录下。这个的好处是,随着代码/配置的规模增加,项目结构不会混乱,仍然能组织良好。
通常一个项目都会有的目录如下:
luffy # 建议全小写
log # 日志目录
conf/config/settings # 配置文件目录
libs/modules # 第三方库目录
core/luffy # 程序代码目录/核心代码目录
docs # 文档库
README # 对软件的说明
setup.py # 快速安装
bin # 程序的启动脚本/程序的入口
luffy_server.py
README的写法:
- 软件定位,软件的基本功能。
- 运行代码的方法: 安装环境、启动命令等。
- 简要的使用说明。
- 代码目录结构说明,更详细点可以说明软件的基本原理。
- 常见问题说明。
关系目录规范的详情可参考: https://www.luffycity.com/python-book/di-4-zhang-python-ji-chu-2014-chang-yong-mo-kuai/ruan-jian-kai-fa-mu-lu-gui-fan.html