美文网首页
3.正则表达式使用基础:括号(一)

3.正则表达式使用基础:括号(一)

作者: BoatingTao | 来源:发表于2019-08-20 22:37 被阅读0次

    3.1分组

    • 假设有这么一个需求,我们需要匹配身份证号码。各位可以思考下怎么写正则表达式。
      身份证号码生成规则:长度15、18位数的字符串,如果是15位,则全是数字,首位不能是0;如果18位,则前17位全是数字,末尾可能是数字或者字母x,首位同样不能是0。
      很正常的,我们可以考虑两套规则:
    15位:[1-9]\d{14}
    18位:[1-9]\d{14}\d{2}[0-9x]
    
    • 但明明这2套规则前面大部分都一样,只是18位的规则后面多了3个字符串而已。这三个字符串要吗出现,要吗出现一次。有没有办法可以一套正则适应2套规则呢。这个时候就可以使用括号()进行分组了。把最后的这个规则作为整体来匹配。
    • (\d{2}[0-9x])
      因此正则表达式可以写成 [1-9]\d{14}(\d{2}[09-x])? 括号的这种功能就叫做分组。例子:希望 ab 重复一次以上,就写作 (ab)+,如果写 ab+,那么+号只限定b。
    re.search(r"^ab+$","ab") != None   #=> True
    re.search(r"^ab+$","abb") != None   #=> True
    re.search(r"^ab+$","abab") != None   #=> False
    
    re.search(r"^(ab)+$","ab") != None   #=> True
    re.search(r"^(ab)+$","abb") != None   #=> False
    re.search(r"^(ab)+$","abab") != None   #=> True
    

    有了分组,就可以准确表示“长度只能是m或者n”

    3.2多选分组

    之前用表达式[1-9]\d{14}(\d{2}[09-x])?匹配身份证号,思路是把18位号码多出的3位“合并”到匹配的15位号码的表达式中。还可以有其他方式。
    15位身份证号就是[1-9]开头,之后是14位数字;18位身份证的开头也是[1-9]的数字,之后是16位数字,最后是[1-9x]?。只需要匹配两种表达式中的一个,就是合法身份证。那我们可以使用多选分组。

    • 多选分组的形式是 (...|...),在括号内以 | 分割多个子表达式,这些子表达式也叫多选分支;
    • 在一个多选结构内,多选分支的数目没有限制。匹配成功时,整个多选分支被视为单个元素,只要其中某个子表达式能够匹配,整个多选结构的匹配都算成功。如果都不能匹配,则整个多选结构匹配失败。回到我们的问题上,我们就可以写2个子表达式来匹配身份证。
    • ([1-9]\d{14}|[1-9]\d{14}\d{2}[09-x]),实现的效果和之前的最后3位分组是一致的。
    • 多选结构比较常见,例如匹配IP地址。要匹配的数字是0~255。思路如下,假设只有一位,那么 \d 即可表示;如果有2位,那么 \d{2} 即可;如果有三位,那么假设第一位数字是1,则后面2位无限制,即 1\d{2} ;如果第一位不是1,而是2,那么第二位数字只能是[0-4],第三位数字无限制,即 2[0-4]\d ;如果第二位数字是5,则第三位数字只能是 [0-5] 。我们可以写表达式:
    (\d|\d{2}|1\d\d|2[0-4]\d|25[0-5])
    

    -关于多选分组,补充三点:
    1.多选结构的一般表示法是(option1|option2),在多选结构中一般会同时使用()和竖线 |;但是如果没有括号,只出现竖线|,仍然是多选结构。

    re.search(r"ab|cd","ab") != None  # =>True
    re.search(r"ab|cd","cd") != None # =>True
    

    括号的用来规定整个多选结构的范围,如果没有出现括号,则整个表达式视为一个多选结构,所以 ab|cd 等价于 (ab|cd),建议多选结构都写出括号。

    • 看起来 [abc] 和 (a|b|c) 一样的,实际上它们能匹配的内容确实一样,但是不推荐使用多选表达式来替代我们的字符组。理由如下:
      1.多选结构更加复杂,不便于书写简单的字符组。 [0-9] 明显比 (0|1|2|3|4|5|6|7|8|9) 简洁。
      2.多选结构每个分支长度没有限制,无法对应到字符组上。
      3.多选结构无法表示排除型字符组。
    • 多选结构的匹配顺序默认是先左侧。例如(hell|hellow),用它来匹配 hellow,结果是hell。
    print(re.search(r"(jeffery|jeff)", "jeffery")).group(0)
    jeffery
    
    print(re.search(r"(jeff|jeffery)", "jeffery")).group(0)
    jeff
    

    最好避免出现相同字符的多选结构,这样匹配会造成大量回溯,影响效率。

    3.3引用分组

    • 括号不仅能把有联系的元素归拢起来并分组,还有其他作用——使用括号后,正则表达式会保存每个分组真正匹配的文本,匹配完成后通过 group(num)之类的方法“引用”分组在匹配时捕获的内容。因为捕获了文本,所以这种功能叫做捕获分组。这种括号叫做捕获型括号
      注意num编号从1开始, 不给参数,默认就是0开始
    result = re.search(r"(\d{4})-(\d{2})-(\d{2})"), "2010-12-22")
    print(result .group(1))
    2010
    
    print(result .group(2))
    12
    
    print(result .group(3))
    22
    
    print(result .group(0))
    2010-12-22
    
    print(result .group())
    2010-12-22
    

    括号还可以嵌套,例如下面的例子,这种比较繁冗。分组的编号此时根据开括号的出现顺序来计数

    manyGroups = r"(((\d{4})-(\d{2}))-(\d{2}))"
    result = re.search(manyGroups, "2010-12-22")
    
    print(result.group(0))
    2010-12-22
    
    print(result.group(1))
    2010-12-22
    
    print(result.group(2))
    2010-12
    
    print(result.group(3))
    2010
    
    print(result.group(4))
    12
    
    print(result.group(5))
    22
    

    3.3正则表达式替换

    • 这里还是以python为例子。 re.sub(pattern, replacement, string)
    print(re.sub(r"[a-z]", " ","1a2b3c"))
    1 2 3
    上述代码是将字符串1a2b3c中的英文字母替换为一个空格
    

    相关文章

      网友评论

          本文标题:3.正则表达式使用基础:括号(一)

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