美文网首页
2.正则表达式使用基础:量词(一)

2.正则表达式使用基础:量词(一)

作者: BoatingTao | 来源:发表于2019-08-10 08:31 被阅读0次

2.1 一般形式

  1. 上一节我们了解到字符组 [0-9] 或 \d 可以匹配单个数字字符。现在我们使用正则来验证更复杂的字符串,比如国内邮政编码。很自然,\d 匹配单个字符,那么我们可以这样写:
  re.search(r"^\d\d\d\d\d\d$", "110016")  !=None   # => True
  1. 这样写的话,太麻烦了, \d 重复了6次,不够灵活方便。为此,正则表达式提供了量词,上面的匹配格式可以简写为 \d{6}。意思就是 匹配 6个数字。

    下面举几个简单的例子:

   re.search(r"^\d{6}$", "100861") !=None  # => True

   re.search(r"^\d{6}$", "1A0861") !=None  # => False
  1. 量词还可以不确定长度,通用形式是 {m,n},注意中间逗号后面不跟空格。它限定之前的元素能够出现的次数,m是下线,n是上限。均为闭区间。\d{4,6},表示这个数字字符的长度最短是4个字符,最长是6个字符。

    量词的限定出现次数一般都有明确下限,如果没用,则默认为0。有些语言可以省略0,写作 {,n},但是这样不是通用的,建议写作 {0,n}。

    下表展示了量词的一般书写形式:

  • {n}之前的元素必须出现n次。

  • {m,n}之前的元素最少出现m次,最多出现n次。

  • {m,}之前的元素最少出现m次,出现次数无上限。(注意:并非真正意义上的无上限,隐式上限是65536 )

  • {0,n}之前的元素可以不出现,也可以出现,最多出现n次。

2.2 常用量词

  1. {m,n} 是通用形式上的量词,正则表达式还有3个常用量词,分别是 +、?、*,它们的形态虽不同于 {m,n},但是功能也相同,可以看作是量词的简记法。

  2. 常用量词书写形式:

  • * 等价于 {0,} 意为可能出现,也可能不出现,出现次数无上限。

  • + 等价于 {1,} 意为至少出现1次,出现次数无上限。

  • * 等价于 {0,1} 意为至多出现1次,也可能不出现。

大部分情况下只需要表示上面这三种意思,所以常用量词的使用频率高于 {m,n},例子如下:匹配 traveler 和 traveller (美式和英式)

re.search(r"^traverll?er", "traveler") !=None  # =>True

re.search(r"^traverll?er", "traveler") !=None  # =>True

量词也广泛用于解析HTML代码,匹配各种标签及标签中的内容。例如匹配所有 html tag的正则表达式:<[^>]+>;匹配 open tag , <[/][>]*>;匹配 close tag ,</[^>]+>;匹配 self-closing tag,<[^>/]+/>

2.3 数据提取

  1. 之前使用的python正则查询函数都是 search(),如果匹配成功,返回一个MatchObject的对象,这个对象包含了匹配的信息,比如匹配的结果。可以使用
re.search(r"^traverll?er", "traveler").group(0)  来获取匹配结果。
  1. 这里再介绍一个python的方法,findall(pattern,string),如果匹配成功,返回的是一个数组。例如:使用findall()来匹配两个邮政编码。注意:search 和 findall 都是python正则表达式库的函数,其他语言不一样。
re.findall(r"\d{6}", "zipcode1:123456, zipcode2:987654")

得到的结果就是 ['123456', '987654'],注意这里我们需要匹配6个数字,所以不需要在正则表达式外面加上 开始 和 $结尾来限定。

2.4 点号

  1. 上一章提到过, "." 号可以匹配任意字符,但是换行符 \n 这种不能匹配。要匹配任意字符可以 [\w\W] 这种。因为点号几乎可以匹配任意字符,所以实际运用中很多人图省事,随意使用 .* 或者 .+ ,结果却事与愿违。下面我们看一个例子:

    我们希望匹配的字符串内容是 "quoted string",待匹配的字符串也是 "quoted string" ,注意这里匹配包含前后双引号。我们这样写没问题:

re.search(r"\".*\"","\"quoted string\"").group(0)   # =>   "quoted string"   
  1. 这样得到的结果没问题,那么我们再变一下。现在我们改变一下待匹配字符串,"quoted string" and another",然后我们用同样的 pattern 去匹配这一段字符串,得到的结果却是 "quoted string" and another",这个结果不是我们想要的 "quoted string" 。
  • 这里作简单解释。在正则表达式 "." 中,点号 "." 可以匹配任何字符, * 表示可以匹配的字符串长度没有限制 ,所以 . 在匹配过程结束以前,每遇到一个字符(除去无法匹配的\n), .*都可以匹配,但是到底匹配这个字符,还是忽略它吗,交给之后的 " 来匹配呢?
  • 答案是取决于所使用的量词。正则中的量词分为几类,之前介绍的量词都可以归为一类,叫做匹配优先量词(也有译为贪婪量词)。意思就是在拿不准是否要匹配的时候,优先尝试匹配,并且几下这个状态,以备“反悔”。
    来分析正则表达式 ".*" 对字符串 "quoted string的匹配过程
  • 开始," 匹配 " ,然后轮到 q , .* 可以匹配它,也可以不匹配,因为使用的量词都是匹配优先量词,所以 .先匹配q,并且记录下这个状态【q也可能是.不该匹配的】;
  • 接下来是字符 u, .* 可与匹配它,也可与不匹配,因为使用的量词都是匹配优先量词,所以 .先匹配g,滨记录下这个状态【g也可能是.不该匹配的】;
  • …………
  • 最后是末尾的 " , .* 可与匹配它,也可与不匹配,因为使用的量词都是匹配优先量词,所以 .先匹配" ,滨记录下这个状态【" 也可能是.不该匹配的】;
    这个时候,字符串后已经没有字符了,但正则表达式中还有 " 没有匹配,所以只能查询之前保存的备用状态,看看能不能退回几步,按照 " 的匹配。查询到最近状态是: 【" 也可能是.不该匹配的】。于是让 . 反悔 对 " 的匹配,把字符串 " 交给 正则里面的 " 来匹配,测试发现正好匹配,所以整个匹配宣告成功。这个反悔的过程,专业术语叫做回溯(backtracking)
    image.png

至于 "quoted string" and another" 也是一样的道理,最开始 .* 匹配了 字符串 * 后的所有内容,后来发现正则中还有 " 未匹配,因此回溯最近的 一个 " ,交给匹配字符李的 " 进行匹配。

image.png
  1. 因此要准确匹配 "quoted string" and another" 字符串中的 "quoted string" ,就不能图省事使用 "." 来匹配,需要使用 "[^"]"
    image.png

2.5 忽略优先量词

  1. 但某些时候,也会需要使用到 .* 匹配,比如匹配 <script type="text/javascript">...</script> ,script标签左右的开关标签好写, 但是js内部的代码可以出现任意字符,所以这个时候还是得 用 .* 来匹配。.* 不能匹配换行符,所以这里用 [\s\S]* 来匹配。
str1 =  """
    <script type="text/javascript">
    alert("1");
    </script>
    <br />
    <script type="text/javascript">
    alert("2");
    </script>
"""
print(re.search(r"<script type=\"text/javascript\">[\s\S]*</script>",str1).group(0))
输出 image.png
  • 表达式是匹配成功了,但是最后的结果不正确。 上述匹配规则会一次性匹配2段JS代码,包括中间的换行符 <BR />。
    换个角度,通过改变 [\s\S]* 的匹配策略来解决问题:在不确定是否需要匹配的场合,先尝试不匹配的选择,测试正则表达式中后面的元素,如果失败,再退回来尝试 .* 匹配,如此就没有问题了。
  • 这就是 忽略优先量词模式(懒惰量词 Lazy Quantifier)。如果不确定是否需要匹配,懒惰量词会选择“不匹配“状态,再尝试表达式中之后的元素,如果尝试失败,再回溯,选择之前保存的匹配状态。
re.search(r"<script type=\"text/javascript\">[\s\S]*?</script>",str1)

再 * 后面增加了 一个 ? 号。这样就能提取出所有 js标签及代码。
匹配优先量词与忽略优先量词逐一对应。所有的匹配优先量词后加 ? 即可。
例如 * 对应 *? 。

忽略优先量词可以提取 c 语言中的护士、提取网页中超链接tag、解析表格等。

  • 使用正则表达式去拆解 linux 路径
print(re.search(r"^.*/"), "/usr/local/bin/pyhton")
  • 拆解windows路径
    print(re.search(r"^.*\"),"c:\program files\")

2.6 转义

  • 前面我们知道了,*、+、? 等作为量词的字符具有特殊意义,但某些情况下我们就要匹配它们本身,则再他们前面加 \ ,例如 +。
  • 如果是 {m,n},则 {m,n}
  • ?? , ??

相关文章

  • 2.正则表达式使用基础:量词(一)

    2.1 一般形式 上一节我们了解到字符组 [0-9] 或 \d 可以匹配单个数字字符。现在我们使用正则来验证更复杂...

  • 正则表达式——知识点

    正则表达式 正则表达式定义的方式 正则表达式使用方法 特殊属性 i/g/m 特殊字符方括号元字符量词补充 RegE...

  • PHP-正则表达式整理

    1.PHP正则表达式函数 2.正则表达式基本语法 界定符,原子,量词,边界控制,模式单元 2.1界定符 表示一个正...

  • day05

    A.你今天学到了什么 1.正则表达式的默认属性 2.正则表达式的test()方法 3.量词的贪婪模式和懒惰模式 4...

  • 正则表达式的使用

    1.正则表达式的语法 iOS开发中正则表达式的基础使用 2.正则表达式不常用的语法 Q:经常看见的正则前面的 (?...

  • 正则表达式中的“量词”入门介绍

    正则表达式中的量词可以用来指明某个字符串匹配的次数。将在以下描述“贪心量词”(Greedy)、“厌恶量词”(rel...

  • 正则表达式的贪婪与非贪婪的例子浅析

    正则表达式种常用的量词X+(1个或多个)、X*(0个或1多个)、X?(0个或1个) 正则表达式默认为贪婪模式,量词...

  • 正则表达式

    简单的正则表达式使用 Greedy 数量词 字符类 预定义字符类 反斜线、转义 反斜线字符 ('') 用于引用转义...

  • linux(十一) 正则

    基础正则表达式字符汇整 延伸型正则表达式 去除注释行和空行 如果使用基础正则表达式 如果是空白行,只有$,这样使用...

  • 关于js正则表达式的贪婪和懒惰模式

    1、量词 正则表达式的量词有:* + ? {}* : 匹配0次到多次+ : 匹配1次到多次? : 匹配0次或1次{...

网友评论

      本文标题:2.正则表达式使用基础:量词(一)

      本文链接:https://www.haomeiwen.com/subject/ofeljctx.html