python正则表达式

  过去在网页解析中,一直使用的都是Xpath,CSS,或者是BS4解析,很少会用到正则,毕竟一个大型网站的前端代码基本上每过一段时间就会更新一次。所以,用正则表达式的话,很容易过段时间就不能正常解析出来想要的结果。相比较来说,在重写的过程中,上面三个所要花费的时间开销比正则要小的多。不过在每次和别人交流的时候,基本上大神都推荐用正则,这个时候难免知其然而不知其所以然。可能是自己的正则用的还不到家,正则在文本匹配中的妙用还是了解的太少。

  一篇写的非常不错的博客:打开链接

  上面提到的博客中的内容不再坠余,这里重点说下正则表达式的扩展表示法。

  1.1 (?iLmsux)(必须放在匹配字符串的开头)

  用户可以直接在正则表达式里面指定一个或者多个标记,而不是通过compile()或者其他re模块函数。

  括号里面的iLmsux表示如下(u并不常用,没有列出):

re.I,re.IGNORECASE	不区分大小写的匹配
re.L,re.LOCALE		根据所使用的本地语言环境通过\w,\W,\b,\B,\s,\S实现匹配
re.M,re.MULTILINE	^和$分别匹配目标字符串中行的起始和结尾,而不是严格匹配整个字符串本身的起始和结尾。
re.S,re.DOTALL		"."(点号)通常匹配除了\n(换行符)之外的所有单个字符;该模式表示"."(点号)能够匹配全部字符。
re.X,re.VERBOSE		通过反斜线转义,否则所有空格加上#(以及在该行中所有后续文字)都被忽略,除非在一个字符串中或者允许注释并且提高可读性。

re.findall(r"(?i)yes", "yes? Yes. YES!") # 忽略大小写的匹配
# ['yes', 'Yes', 'YES']
text = """
The first line
the second line
the third line
"""
re.findall(r"th.+", text) # 不使用多行匹配
# ['the second line', 'the third line']
re.findall(r"(?s)th.+", text)# 进行多行匹配
# ['the second line\nthe third line\n']
re.findall(r"(?is)th.+", text)# 忽略大小写的多行匹配
# ['The first line\nthe second line\nthe third line\n']
# 使用拆分的模式串进行匹配电话号,这样更加便于理解,这也可以说是re.X的用处所在
re.search(r"""(?x)
\((\d{3})\) # 匹配区号
[ ]         # 匹配空白符
(\d{3})     # 前缀
-           # 横线
(\d{4})     # 终点数字
""", '(010) 555-1212').groups()
# ('010', '555', '1212')

  1.2 (?:...)

  通过使用该符号,可以对部分正则表达式进行分组,但是并不会保存该分组用于后续的检索或者应用。

text = """
http://google.com
http://www.google.com
http://code.google.com
"""
re.findall(r"http://(?:\w+\.)*(\w+\.com)", text)
# ['google.com', 'google.com', 'google.com'] 观察输出结果可以发现(?:...)中的内容并没有保留

  1.3 (?P) 起别名,使用名称标识符来保存匹配

re.search(r"\((?P\d{3})\) (?P\d{3})-(?:\d{4})", '(010) 555-1212').groupdict()
# {'name1': '010', 'name2': '555'}

# 使用\g(name)标识符来检索保存的匹配
re.sub(r"\((?P\d{3})\) (?P\d{3})-(?:\d{4})", "(\g) \g-xxxx", "(010) 555-1212")
# '(010) 555-xxxx'

  1.4 (?P=name)

  可以在一个相同的正则表达式中重用模式,而不必稍后再次在(相同)正则表达式中指定相同的模式。

  不会保留该分组用于以后的检索或者应用。

text = "(010) 555-1212 010-555-1212 10105551212"
bool(re.match(r"""(?x)
         # 匹配 (010) 555-1212
         \((?P\d{3})\)[ ](?P\d{3})-(?P\d{4})
         [ ]
         # 开始重用模式
         # 匹配 010-555-1212
         (?P=name1)-(?P=name2)-(?P=name3)
         [ ]
         # 匹配 10105551212
         1(?P=name1)(?P=name2)(?P=name3)
""", text))
# True

text = """
Guido van Rossum
Tim Peters
Alex Martelli
Just van Rossum
Raymond Hettinger
"""
# 只有当一个字符串后面跟着 van Rossum的时候才做匹配操作
re.findall(r"\w+(?= van Rossum)", text)
# ['Guido', 'Just']

  1.5 (?!...)

# 忽略以 noreply 和 postmaster 开头的e-mail地址
text = """
    [email protected]
    [email protected]
    [email protected]
    [email protected]
    [email protected]
"""
# (?m)不严格匹配整个字符串的起始和结尾
# 之后的字符串需要不匹配(?!...)表达式才能够匹配成功
re.findall(r'(?m)^\s+(?!noreply|postmaster)(\w+)', text)
# ['sales', 'eng', 'admin']


# 使用finditer迭代器
["%[email protected]" % e.group(1) for e in re.finditer(r'(?m)^\s+(?!noreply|postmaster)(\w+)', text)]
# ['[email protected]', '[email protected]', '[email protected]']

  1.6 (?=...) 

  (?=.com) 当一个字符串后面跟着.com才做匹配操作。

text = "[email protected]"
re.findall(r"\w+(?=.com)", text)
# ['gmail']
  1.7 (?<=...)
  (?<=010) 如果字符串之前为"010"才做匹配。

text = "(010) 555-1212"
re.findall("(?<=\(\d{3}\)) (\d{3})-(\d{4})", text)
# [('555', '1212')]
  1.8 (?

  (?

pat=re.compile(r'(?

  1.9 (?(id|name)Y|N)

  (?(1)Y|N) 如果匹配组1(\1)存在,就与Y匹配,否则,就与X匹配。|N为可选项

re.findall(r"(\d)?abc(?(1)\d|abc)", "1abc2")
# ['1']


#"(?(id/name) yes |no)": 组是否匹配,匹配返回
pat=re.compile(r'a(\d)?bc(?(1)\d)')   #no省略了,完整的是a\dbc\d ==> a2bc3,总共5位,第2位是可有可无的数字,第5为是数字
print pat.findall('abc9')                   #返回组1,但第2位(组1)没有,即返回了''
print pat.findall('a8bc9')                  #完整的模式,返回组1
print pat.match('a8bc9').group()
print pat.match('a8bc9').group(1)
print pat.findall('a8bc')                   #第5位不存在,则没有匹配到
# ['']
# ['8']
# a8bc9
# 8
# [] 


  Python正则表达式中常用的扩展表示法基本上就是这些,还有一些目前并没有用到过,等用到的时候再进行总结!!!

你可能感兴趣的:(python,网络爬虫)