机器学习之字符正则匹配

           正则表达式 (Regular Expression) 又称 RegEx, 是用来匹配字符的一种工具. 在一大串字符中寻找你需要的内容. 它常被用在很多方面, 比如网页爬虫, 文稿整理, 数据筛选等等. 最简单的一个例子, 比如我需要爬取网页中每一页的标题. 而网页中的标题常常是这种形式.

<title>我是标题</ title>

而且每个网页的标题各不相同, 我就能使用正则表达式, 用一种简单的匹配方法, 一次性选取出成千上万网页的标题信息. 正则表达式绝对不是一天就能学会和记住的, 因为表达式里面的内容非常多, 强烈建议, 现在这个阶段, 你只需要了解正则里都有些什么, 不用记住, 等到你真正需要用到它的时候, 再反过头来, 好好琢磨琢磨, 那个时候才是你需要训练自己记住这些表达式的时候.

如果需要找到潜在的多个可能性文字, 我们可以使用 [] 将可能的字符囊括进来. 比如 [ab] 就说明我想要找的字符可以是 a 也可以是 b. 这里我们还需要注意的是, 建立一个正则的规则, 我们在 pattern 的 “” 前面需要加上一个 r 用来表示这是正则表达式, 而不是普通字符串. 通过下面这种形式, 如果字符串中出现 “run” 或者是 “ran”, 它都能找到.

# multiple patterns ("run" or "ran")
ptn = r"r[au]n"       # start with "r" means raw string
print(re.search(ptn, "dog runs to cat"))    # <_sre.SRE_Match object; span=(4, 7), match='run'>

同样, 中括号 [] 中还可以是以下这些或者是这些的组合. 比如 [A-Z] 表示的就是所有大写的英文字母. [0-9a-z] 表示可以是数字也可以是任何小写字母.

print(re.search(r"r[A-Z]n", "dog runs to cat"))     # None
print(re.search(r"r[a-z]n", "dog runs to cat"))     # <_sre.SRE_Match object; span=(4, 7), match='run'>
print(re.search(r"r[0-9]n", "dog r2ns to cat"))     # <_sre.SRE_Match object; span=(4, 7), match='r2n'>
print(re.search(r"r[0-9a-z]n", "dog runs to cat"))  # <_sre.SRE_Match object; span=(4, 7), match='run'>

按类型匹配 

除了自己定义规则, 还有很多匹配的规则时提前就给你定义好了的. 下面有一些特殊的匹配类型给大家先总结一下, 然后再上一些例子.

  • \d : 任何数字
  • \D : 不是数字
  • \s : 任何 white space, 如 [\t\n\r\f\v]
  • \S : 不是 white space
  • \w : 任何大小写字母, 数字和 “” [a-zA-Z0-9]
  • \W : 不是 \w
  • \b : 空白字符 (在某个字的开头或结尾)
  • \B : 空白字符 (在某个字的开头或结尾)
  • \\ : 匹配 \
  • . : 匹配任何字符 (除了 \n)
  • ^ : 匹配开头
  • $ : 匹配结尾
  • ? : 前面的字符可有可无

模糊匹配(https://www.cnblogs.com/dangrui0725/p/9446639.html

# re模块 正则表达式,对字符串进行模糊匹配
import re

# 元字符:. ^ $ * + ? {} [] | () \

# . 代表任意的一个符号,除了\n

# ^ 代表必须是从字符串的开头进行匹配

# $ 代表必须是从字符串的结尾进行匹配

# * 代表按*左边的字符进行匹配,包含0-无穷次 默认贪婪匹配,按最多的进行匹配

# + 代表按+左边的字符进行匹配,包含1-无穷次 默认贪婪匹配,按最多的进行匹配

# ? 代表按?左边的字符进行匹配,包含0-1次 默认贪婪匹配,按最多的进行匹配

# | 代表匹配左边的字符或右边的字符

# () 分组,将()中的字符作为一个整体

# (?P<分组名>正则) 命名分组,将取到的结果放到相应的分组名下

# {} 定义匹配的范围 默认贪婪匹配,按最多的进行匹配
# {0, }  表示0到穷次 相当于*
# {1, }  表示1到无穷次,相当于+
# {0,1}  表示0到1次,相当于?

# 将贪婪匹配改为惰性匹配,只需要在上面几个元字符后加?

# [] 字符集 字符集中的字符都是或的作用,在字符集有功能的符号是 - ^ \
# - 代表左边的字符到右边的字符
# [a-z] 代表a到z
# [A-Z] 代表A到Z
# [0-9] 代表0到9
# ^ 代表非
# [^a-z] 代表非a-z的所有字符

# \ 代表转义符,后面跟元字符则去除特殊功能,后面跟某些字符实现特殊功能
# \d 匹配任何十进制数;相当于[0-9]
# \D 匹配任何非数字字符;相当于[^0-9]
# \s 匹配任何空白字符; 相当于[\t\n\r\f\v]
# \S 匹配任何非空白字符; 相当于[^\t\n\r\f\v]
# \w 匹配任何字母数字字符与下划线;相当于[a-zA-Z0-9_]
# \W 匹配任何非字母数字字符与下划线;相当于[^a-zA-Z0-9_]
# \b 匹配任何一个特殊字符边界;如空格 & # 等
# 因为的python中,\b代表转义字符退格,当引入re模块想使用\b来匹配任何一个特殊字符边界时,应当使用\\b

下面就是具体的举例说明啦.

# \d : decimal digit
print(re.search(r"r\dn", "run r4n"))           # <_sre.SRE_Match object; span=(4, 7), match='r4n'>
# \D : any non-decimal digit
print(re.search(r"r\Dn", "run r4n"))           # <_sre.SRE_Match object; span=(0, 3), match='run'>
# \s : any white space [\t\n\r\f\v]
print(re.search(r"r\sn", "r\nn r4n"))          # <_sre.SRE_Match object; span=(0, 3), match='r\nn'>
# \S : opposite to \s, any non-white space
print(re.search(r"r\Sn", "r\nn r4n"))          # <_sre.SRE_Match object; span=(4, 7), match='r4n'>
# \w : [a-zA-Z0-9_]
print(re.search(r"r\wn", "r\nn r4n"))          # <_sre.SRE_Match object; span=(4, 7), match='r4n'>
# \W : opposite to \w
print(re.search(r"r\Wn", "r\nn r4n"))          # <_sre.SRE_Match object; span=(0, 3), match='r\nn'>
# \b : empty string (only at the start or end of the word)
print(re.search(r"\bruns\b", "dog runs to cat"))    # <_sre.SRE_Match object; span=(4, 8), match='runs'>
# \B : empty string (but not at the start or end of a word)
print(re.search(r"\B runs \B", "dog   runs  to cat"))  # <_sre.SRE_Match object; span=(8, 14), match=' runs '>
# \\ : match \
print(re.search(r"runs\\", "runs\ to me"))     # <_sre.SRE_Match object; span=(0, 5), match='runs\\'>
# . : match anything (except \n)
print(re.search(r"r.n", "r[ns to me"))         # <_sre.SRE_Match object; span=(0, 3), match='r[n'>
# ^ : match line beginning
print(re.search(r"^dog", "dog runs to cat"))   # <_sre.SRE_Match object; span=(0, 3), match='dog'>
# $ : match line ending
print(re.search(r"cat$", "dog runs to cat"))   # <_sre.SRE_Match object; span=(12, 15), match='cat'>
# ? : may or may not occur
print(re.search(r"Mon(day)?", "Monday"))       # <_sre.SRE_Match object; span=(0, 6), match='Monday'>
print(re.search(r"Mon(day)?", "Mon"))          # <_sre.SRE_Match object; span=(0, 3), match='Mon'>

如果一个字符串有很多行, 我们想使用 ^ 形式来匹配行开头的字符, 如果用通常的形式是不成功的. 比如下面的 “I” 出现在第二行开头, 但是使用 r"^I" 却匹配不到第二行, 这时候, 我们要使用 另外一个参数, 让 re.search() 可以对每一行单独处理. 这个参数就是 flags=re.M, 或者这样写也行 flags=re.MULTILINE.

string = """
dog runs to cat.
I run to dog.
"""
print(re.search(r"^I", string))                 # None
print(re.search(r"^I", string, flags=re.M))     # <_sre.SRE_Match object; span=(18, 19), match='I'>

重复匹配 

如果我们想让某个规律被重复使用, 在正则里面也是可以实现的, 而且实现的方式还有很多. 具体可以分为这三种:

  • * : 重复零次或多次
  • + : 重复一次或多次
  • {n, m} : 重复 n 至 m 次
  • {n} : 重复 n 次

举例如下:

# * : occur 0 or more times
print(re.search(r"ab*", "a"))             # <_sre.SRE_Match object; span=(0, 1), match='a'>
print(re.search(r"ab*", "abbbbb"))        # <_sre.SRE_Match object; span=(0, 6), match='abbbbb'>

# + : occur 1 or more times
print(re.search(r"ab+", "a"))             # None
print(re.search(r"ab+", "abbbbb"))        # <_sre.SRE_Match object; span=(0, 6), match='abbbbb'>

# {n, m} : occur n to m times
print(re.search(r"ab{2,10}", "a"))        # None
print(re.search(r"ab{2,10}", "abbbbb"))   # <_sre.SRE_Match object; span=(0, 6), match='abbbbb'>

分组 

我们甚至可以为找到的内容分组, 使用 () 能轻松实现这件事. 通过分组, 我们能轻松定位所找到的内容. 比如在这个 (\d+) 组里, 需要找到的是一些数字, 在 (.+) 这个组里, 我们会找到 “Date: “ 后面的所有内容. 当使用 match.group() 时, 他会返回所有组里的内容, 而如果给 .group(2) 里加一个数, 它就能定位你需要返回哪个组里的信息.

match = re.search(r"(\d+), Date: (.+)", "ID: 021523, Date: Feb/12/2017")
print(match.group())                   # 021523, Date: Feb/12/2017
print(match.group(1))                  # 021523
print(match.group(2))                  # Date: Feb/12/2017

有时候, 组会很多, 光用数字可能比较难找到自己想要的组, 这时候, 如果有一个名字当做索引, 会是一件很容易的事. 我们字需要在括号的开头写上这样的形式 ?P<名字> 就给这个组定义了一个名字. 然后就能用这个名字找到这个组的内容.

match = re.search(r"(?P<id>\d+), Date: (?P<date>.+)", "ID: 021523, Date: Feb/12/2017")
print(match.group('id'))                # 021523
print(match.group('date'))              # Date: Feb/12/2017

断言

正则断言的使用

  • 零宽断言

    • 匹配宽度为零,满足一定的条件/断言。
    • 零宽断言用于查找在某些内容(但并不包括这些内容)之前或之后的东西,也就是说它们像\b,^,$那样用于指定一个位置,这个位置应该满足一定的条件(即断言),因此它们也被称为零宽断言。
    • 断言用来声明一个应该为真的事实。正则表达式中只有当断言为真时才会继续进行匹配
  • 零宽断言又分四种

    • 先行断言(零宽度正预测先行断言)

      • 表达式:(?=表达式)
      • 表示匹配表达式前面的位置
      • 先行断言的执行步骤是这样的先从要匹配的字符串中的最右端找到第一个ing(也就是先行断言中的表达式)然后 再匹配其前面的表达式,若无法匹配则继续查找第二个ing 再匹配第二个 ing前面的字符串,若能匹配 则匹配
      • .*(?=d) 可c以匹配abcdefghi 中的abc
    • 后发断言(零宽度正回顾后发断言)

      • 表达式: (?<=表达式)
      • 表示匹配表达式后面的位置
      • 后发断言跟先行断言恰恰相反 它的执行步骤是这样的:先从要匹配的字符串中的最左端找到第一个abc(也就是先行断言中的表达式)然后 再匹配其后面的表达式,若无法匹配则继续查找第二个abc 再匹配第二个abc后面的字符串,若能匹配 则匹配
      • 例如(?<=abc).* 可以匹配abcdefg中的defg
    • 负向断言

      • 负向零宽先行断言 :(?!表达式)

      • 负向零宽后发断言:(?<!表达式)

      • 负向零宽断言 (?!表达式) 也是匹配一个零宽度的位置,不过这个位置的“断言”取表达式的反值,例如 (?!表达式) 表示 表达式 前面的位置,如果 表达式 不成立 ,匹配这个位置;如果 表达式 成立,则不匹配:同样,负向零宽断言也有“先行”和“后发”两种,负向零宽后发断言为 (?<!表达式)

参考链接:https://morvanzhou.github.io/tutorials/python-basic/basic/13-10-regular-expression/

https://www.cnblogs.com/he-qing-qing/p/11331080.html

2、BeautifulSoup

BeautifulSoup是一个可以从HTML或XML文件中提取数据的python库,简单来说,他能将HTML的标签文件解析成树形结构,然后方便地获取到指定标签的对应属性。通过beautifulsoup库,可以将指定的class或id值作为参数直接获取对应标签的相关数据。

 


补:

正则表达式中re.match、re.search、re.findall,re.finditer的用法和区别
re.match语法:re.match(pattern,string,flags=0)  ##从字符起始位置匹配,若起始位置匹配不成功返回none。即只匹配起始位置

re.search可以扫描整个字符串并返回第一个成功的匹配。

re.findall可以找到所有满足匹配条件的结果,并以列表的形式返回,而上面两者只能返回一个值。

re.finditer返回string中所有与pattern相匹配的全部字串,返回形式为迭代器。

å¨è¿éæå¥å¾çæè¿°

参考链接:https://blog.csdn.net/qq_42156420/article/details/80784673

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xiaomu_347

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值