上次课讲到使用正则表达式和不使用正则表达式进行字符串查找的对比,可以看出使用正则表达式进行字符串查找时,代码更加简洁也更加灵活。最后还提到了字符组的概念。 本次课我们就来更加详细地讲解下字符组。
# 1.字符组范围表示法
上次课我们讲到使用正则表达式来查找字符串,代码如下:
import re
mo = re.search(r"[0123456789][0123456789][0123456789]-[0123456789][0123456789][0123456789]-[0123456789][0123456789][0123456789][0123456789]", "My number is 415-555-4242")
print("Phone number found: " + mo.group())
2
3
4
5
上面的代码中,字符组 [0123456789] 的表示方法是很繁琐的,那有没有简单的方法呢?答案是使用字符组的范围表示法,[0123456789] 可以用范围表示法表示为 [0-9]。于是,上述代码使用范围表示法可以改写成:
import re
mo = re.search(r"[0-9][0-9][0-9]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]", "My number is 415-555-4242")
print('Phone number found: ' + mo.group())
2
3
4
5
# 2.字符组简记法
针对数字、字母以及空白字符等常见字符,正则表达式提供了更简洁的表示法。常见的字符组简记法有 \d、 \w、 \s ,其中 \d 等价于 [0-9] ,其中 d 代表数字;\w 等价于 [0-9a-zA-Z] ,其中 w 代表单词字符;\s 等价于 [ \t\r\n\v\f](第一个字符是空格),s 表示空白字符。使用字符组简记法,上述代码可以改写成:
import re
mo = re.search(r"\d\d\d-\d\d\d-\d\d\d\d", "My number is 415-555-4242")
print('Phone number found: ' + mo.group())
2
3
4
5
# 3.排除性字符组
字符组是匹配在一个位置可能出现的所有字符,有时候使用字符组匹配某个位置上可能出现的所有字符不是很方便,反而表示这个位置上不会出现的字符很方便。如果要表示某个位置上不会出现的字符,便用到了排除性字符组。例如当我们要匹配一个字符串中的所有非元音字符时,代码如下:
import re
mo = re.findall(r"[^aeiouAEIOU]", "RoboCop eats baby Iood. BABY FOOD")
for match in mo:
print(match)
2
3
4
5
上面的代码中我们使用排除性字符组 [^aeiouAEIOU] 来表示所有的非元音字符。排除型字符组非常类似普通字符组,只是在开方括号 [ 之后紧跟一个脱字符 ^,表示在当前位置匹配一个没有列出的字符。
相对于 \d、\w 和 \s 这三个普通字符组简记法,正则表达式也提供了对应排除型字符组的简记法:\D、\W 和 \S,字母完全一样,只是改为大写。这些简记法匹配的字符互补:\s 能匹配的字符,\S 一定不能匹配;\w 能匹配的字符,\W 一定不能匹配;\d 能匹配的字符,\D 一定不能匹配。
# 4.匹配开头和结尾
前面讲的字符串匹配都是用正则表达式去匹配字符串的一部分。除了部分匹配外,我们还有完全匹配、只匹配开头、只匹配结尾等需求。
# 4.1 匹配开头和结尾
import re
mo = re.search(r"^\d\d\d-\d\d\d-\d\d\d\d$", "My number is 415-555-4242")
print(mo == None)
2
3
4
5
为了进行完全匹配,只要在正则表达式的开头加上 ^ 字符,在结尾加上 $ 字符。由于进行的是完全匹配,所以上面的代码输出 True,也就是没有匹配到。下面将上述代码更改为如下形式:
import re
mo = re.search(r"^\d\d\d-\d\d\d-\d\d\d\d$", "415-555-4242")
print('Phone number found: ' + mo.group())
2
3
4
5
这样便可以匹配到电话号码了。
# 4.2 匹配结尾
为了进行尾部匹配,只要在正则表达式的尾部加上 $ 字符。代码如下:
import re
mo = re.search(r"\d\d\d-\d\d\d-\d\d\d\d$", "My number is 415-555-4242")
print("Phone number found: " + mo.group())
2
3
4
5
由于字符串的结尾刚好是电话号码,所以用尾部匹配是可以匹配到电话号码的。
# 4.3 匹配开头
为了进行头部匹配,只要在正则表达式的头部加上 ^ 字符。代码如下:
import re
mo = re.search(r"^\d\d\d-\d\d\d-\d\d\d\d", "My number is 415-555-4242")
print(mo == None)
2
3
4
5
由于进行的是头部匹配,所以上面的代码输出 True,也就是没有匹配到。下面将上述代码更改为如下形式:
import re
mo = re.search(r"^\d\d\d-\d\d\d-\d\d\d\d", "415-555-4242 is a number")
print("Phone number found: " + mo.group())
2
3
4
5
由于现在字符串的头部刚好是电话号码,所以用头部匹配是可以匹配到电话号码的。
# 5.匹配特殊字符
在正则表达式中,以下字符具有特殊含义: . ^ $ * + ? { } [ ] \ | ( ) 如果需要从字符串中匹配出以上具有特殊含义的字符,需要对以上字符进行转义: . ^ $ * + ? { } [ ] \ | ( )。我们举个匹配括号的例子,代码如下:
import re
mo = re.search(r"\(\d\d\d\)-\d\d\d-\d\d\d\d", "My number is (415)-555-4242")
print("Phone number found: " + mo.group())
2
3
4
5
上面代码在进行匹配时,对括号进行了转义。