很喜欢Python教材中的这句格言:
有些人面临问题时会想:“我知道, 我将使用正则表达式来解决这个问题.”
这让他们面临的问题变成了两个. ---------Jamie Zawinski
正则表达式的确好用,但是复杂的模式难以阅读和维护,与其把花在研究用正则表达式处理复杂的问题上,还不如把时间花在如何写一套清晰,易维护的逻辑上(但是为什么要用,还是因为爽啊)
关于正则表达式的语法,可以参阅我的这篇[学习笔记]正则表达式语法与使用速查
re模块
“我觉得学习是一个循序渐进的过程,所以我不一次性列出所有的函数,这里只列出例子要用的函数.”
函数 | 描述 |
---|---|
compile(pattern,[, flags]) | 根据包含正则表达式的字符串创建模式对象 |
search(pattern,string[, flags]) | 在字符串中查找模式 |
sub(pat, repl, string[, count=0]) | 对字符串中域模式pat匹配的子串都替换为repl |
函数
re.compile()
将字符串表示的正则表达式转换为模式对象,提高匹配效率,调用re.search()
等函数时,如果使用的是字符串表示的正则表达式,会在内部先转换为模式对象再使用.如果转为模式对象后,则后面每次使用正则表达式都无需进行转换.即re.search(pat,string)
等价于pat.search(string)
例如查找"http://www.python.org"
中的python
并替换为java
import re
line="http://www.python.org"
pat="(?<=\.).+(?=\.)" #两个.之间的内容
patobj=re.compile(pat) #创建模式对象
print(re.search(pat, line))
print(re.search(patobj, line)) #正则表达式与模式对象都能使用
print(patobj.search(line))
#输出结果
<re.Match object; span=(11, 17), match='python'>
<re.Match object; span=(11, 17), match='python'>
<re.Match object; span=(11, 17), match='python'>
函数
re.search
在给定字符串中查找第一个与指定pat
匹配的子串,如果找到将返回MatchObject
(结果为True
),否则为None
.(结果为False
)
观察结果<re.Match object; span=(11, 17), match='python'>
,发现MatchObject
的匹配子串为'python'
,起始与终止位置为11,17
替换为java
line1 = re.sub(pat, "java", line)
line2 = patobj.sub("java", line)
print(line1)
print(line2)
#输出结果
http://www.java.org
http://www.java.org
函数 | 描述 |
---|---|
match(pattern, string,[, flags]) | 在字符串开头匹配模式 |
split(pattern, string,[, maxsplit=0]) | 根据模式来分割字符串 |
findall(pattern, string) | 返回一个列表,其中包含字符串中所有与模式匹配的子串 |
函数
re.match
尝试在给定字符串开头查找与正则表达式匹配的子串,和re.search
相似,如果找到这样的子串,返回MatchObject
,否则返回None
另外,re.match
在模式与字符串开头匹配时就返回True
,而不要求与整个字符串匹配,如果要求完全匹配,需要在模式末尾加上$
,从而将匹配检查延伸到整个字符串.
实例:找出以http协议开头的网址
line1 = "http://www.python.org"
line2 = "ftp://192.168.1.1"
patobj = re.compile("http.*")
print(patobj.match(line1))
print(patobj.match(line2))
print(re.match("w{3}.*",line1)) #不是开头匹配
#输出结果
<re.Match object; span=(0, 21), match='http://www.python.org'>
None
None
函数
re.split
类似于字符串方法str.split
,但使用正则表达式来指定分隔符,而不是固定的分隔符
实例:分割字符串中的网址
text="qq.com, baidu.com,,, python.org csdn.net"
patobj=re.compile('[, ]+')
print(patobj.split(text))
print(patobj.split(text,1))#指定分割次数maxsplit
#输出结果
['qq.com', 'baidu.com', 'python.org', 'csdn.net']
['qq.com', 'baidu.com,,, python.org csdn.net']
函数
re.findall
返回一个列表,其中包含所有与给定模式匹配的子串```
实例:分割java代码行中的所有的单词以及逐个标点
text="public static void main(String[] args){ String str='...I'm fine.And you? --he said.';}"
print(re.findall('[\w]+',text))
print(re.findall('[\W]+',text))
#输出结果
['public', 'static', 'void', 'main', 'String', 'args', 'String', 'str', 'I', 'm', 'fine', 'And', 'you', 'he', 'said']
[' ', ' ', ' ', '(', '[', ']', ' ', ')', '{', ' ', ' ', '=', "'", '.', '.', '.', "'", ' ', '.', ' ', '?', ' ', '-', '-', ' ', '.', "'", ';', '}']
匹配对象和编组
方法 | 描述 |
---|---|
group([group1,…]) | 获取与给定子模式(编组)匹配的子串 |
start([group]) | 返回与给定编组匹配的子串的起始位置 |
end([group]) | 返回与给定编组匹配的子串的终止位置(与切片一样,不包含终止位置) |
span([group]) | 返回与给定编组匹配的子串的起始和终止位置 |
在模块
re
中,查找与模式匹配的子串的函数,在找到时返回MatchObject
对象.
它包含了:
1.与模式匹配的子串的信息 2.模式的哪部分与子串哪部分匹配的信息.子串部分称为编组
例如: 模式’(I am a (student)) who (live in (Guangzhou))’ 就包含了以下编组:
编组序号 子串 0(整个模式) I am a student who live in Guangzhou 1 I am a student 2 student 3 live in Guangzhou 4 Guangzhou 通过创建这样模式,可以提取出感兴趣,有不同意义的部分
text = "I am a student who live in Guangzhou" pat = '(I am a (student)) who (live in (Guangzhou))' for i in range(5): print(re.search(pat, text).group(i)) #输出结果 I am a student who live in Guangzhou I am a student student live in Guangzhou Guangzhou
实例:提取网址中的不同部分
pat = re.compile('(^.*//)(.*)\.(.+)\.(.*?)/(.*)')
text = "http://www.abc.com/docs/index.html"
label = ["[Address]", "[Protocol]", "[Domain]", "[Main]", "[Suffix]", "[Doc]"]
for i in range(6):
print(label[i], re.search(pat, text).group(i))
#输出
[Address] http://www.abc.com/docs/index.html
[Protocol] http://
[Domain] www
[Main] abc
[Suffix] com
[Doc] docs/index.html
#
text = "https://docs.python.org/3/whatsnew/3.7.html" #更换地址
for i in range(6):
print(label[i], re.search(pat, text).group(i))
#输出
[Address] https://docs.python.org/3/whatsnew/3.7.html
[Protocol] https://
[Domain] docs
[Main] python
[Suffix] org
[Doc] 3/whatsnew/3.7.html
具体实例:模板替换
在已经标注好相应标签的Java代码中,应用模板转换为HTML代码,这里以转换注释为例
labeled_code = \
[
' [note=/* @author xxx]',
' [note=* @since 1.1] ',
' [note= */]',
'public boolean isTranslate(int octal , int flags){',
'[note=//...Some codes to realize]',
'return true; ',
'}'
]
note_pat = re.compile("\[note=(.+)]") # 注释模式
for text in labeled_code:
note_match = note_pat.search(text) # 返回MatchObject
if note_match:
note_text = note_match.group(0)
note_repl = "<span class='note'> " + note_match.group(1) + " </span>"
text = text.replace(note_text, note_repl) # 替换注释
print(text)
输出结果:
<span class='note'> /* @author xxx </span>
<span class='note'> * @since 1.1 </span>
<span class='note'> */ </span>
public boolean isTranslate(int octal , int flags){
<span class='note'> //...Some codes to realize </span>
return true;
}
加上css选择器和相应标签就能实现语法高亮效果
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
.note{
color:#000080;
font-weight:bold;
font-style:italic;}
</style>
</head>
<body>
<pre>
<!--此处填入转换的html代码-->
</pre>
</body>
</html>
效果如下: