引例
判断数字字符
def isDigit(ch):
return re.search(ch, "[0-9]") != None
-
这里真正要关心的就是正则表达式[0-9],它表示“从0到 9之间的任意字符"
re.search()是正则表达式运算函数,它判断ch能否由正则表达 式[0~9]匹配,可以则返回一个结果,否则返回None
判断字符串str是否电话号码
return re.search(str, "[1-9][0-9](6,7}") != None
- 这个正则表达式最开始是[1-9],表示第一个字符必须是1〜9之间的数字字符;之后是 [0-9] {6,7},表示长度在6和7之间,由0〜9之间的数字字符组成的字符串(两部分加起来, 整个字符串的长度在7和8之间)。
找出一段文本中所有的固定电话号码
return re.findall(str, '(?<![0~9])[1-9][0-9]{6,7}(?![0-9])')
- 这个正则表达式之前多出了(?<! [0-9〕),表示“之前不能是[0-9]之后多出了 (?! [0-9]),表示“之后不能是[0-9]虽然稍微复杂点,但意思明确,而且不难理解
正文
普通字符组
字符组(CharacterClass) 是正则表达式最基本的结构之一,要理解正则表达式的’‘灵活”, 认识它是第一步。
顾名思义,字符组就是一组字符,在正则表达式中,它表示“在同一个位置可能出现的各种 字符”,其写法是在一对方括号[和]之间列出所有可能出现的字符,简单的字符组比如[ab]、 [314]、[#・?]在解决一些常见问题时,使用字符组可以大大简化操作,下面举“匹配数字字符” 的例子来说明。
字符可以分为很多类,比如数字、字母、标点等。有时候要求“只出现一个数字字符”,换 句话说,这个位置上的字符只能是0、1、2、…、8、9这10个字符之一。要进行这种判断,通 常的思路是:用10个条件分别判断字符是否等于这10个字符,对10个结果取“或”,只要其中 一个条件成立,就返回True,表示这是一个数字字符
介绍完关于Python的基础知识,继续讲解字符组。字符组中的字符排列顺序并不影响字符 组的功能,出现重复字符也不会影响,所以[0123456789]完全等价于[9876543210]、 [1029384756]、 [9988876543210]。
不过,代码总是要容易编写,方便阅读,正则表达式也是一样,所以一般并不推荐在字符组 中出现重复字符。而且,还应该让字符组中的字符排列更符合认知习惯,比如[0123456789] 就好过[0192837465]。为此,正则表达式提供了-范围表示法(range),它更直观,能进一步 简化字符组。
所谓“范围表示法”,就是用也丑的形式表示X到y整个范围内的字符,省去一一列出的麻烦,这样[0123456789]就可以表示为[0-9]。如果你觉得这不算什么,那么确实比 [abcdefghi j klmnopqrstuvwxyz ]简单太多了。
你可能会问,“范围表示法’'的范围是如何确定的?为什么要写作[0-9],而不写作[9-0]?
要回答这个问题,必须了解范围表示法的实质。在字符组中,二表示的范围,一般是根据字 符对应的码值(Code Point,也就是字符在对应编码表中的编码的数值)来确定的,码值小的字 符在前,码值大的字符在后。在ASCII编码中(包括各种兼容ASCII的编码中),字符0的码值 是48 (十进制),字符9的码值是57 (十进制),所以[0-9]等价于[0123456789];而[9-0] 则是错误的范围,因为9的码值大于0,所以会报错。
正则表达式判断数字字符
re.search("[0123456789“], charStr) != None
re.search()是Python提供的正则表达式操作函数,表示“进行正则表达式匹配”;charStr 仍然是需要判断的字符串,而[0123456789]则是以字符串形式给出的正则表达式,它是一个字 符组,表示“这里可以是0、1、2、…、8、9中的任意一个字符。只要charStr与其中任何一个 字符相同(或者说“charStr可以由[0123456789]匹配"),就会得到一个Matchobject对象;否则,返回None所以判断结果是否为None, 就可以判断charStr是否是数字字符。
正则表达式判断数字字符在各种语言中的应用
NET (C#)
〃能匹配则返回true,否则返回false
Regex.IsMatch(charStr, "[0123456789]H;
Java
〃能匹配则返回true,否则返回false
charStr.matches("[0123456789]");
JavaScript
〃能匹配则返回true,否则返回false
[0123456789]/.test(charStr);
PHP
〃能匹配则返回1,否则返回。
preg_match('/[0123456789]/", charStr);
Python
#能匹配则返回RegexObject,否则返回None
re.search("[0123456789]", charStr)
Ruby
#能匹配则返回。,否则返回nil
charStr =~ /[0123456789]/
[0-9a-fA-F]准确判断十六进制字符
re.search("^[0-9a-fA-F]$","0") != None # => True
re.search("^[0-9a-fA-F]$","c") != None # => True
re.search("^[0-9a-fA-F]$","i") != None # => False
re.search("^[0-9a-fA-F]$","C") != None # => True
re.search("^[0-9a-fA-F]$","J") != None # => False
在不少语言中,还可以用转义序列\xAex来表示一个字符,其中\x是固定前缀,表示转义序 列的开头,是字符对应的码值(Code Point,详见第127页,下文用行127表示),是一个两 位的十六进制数值。比如字符A的码值是41 (十进制则为65),所以也可以用\x41表示。
字符组中有时会出现这种表示法,它可以表现一些难以输入或者难以显示的字符,比如\x7F; 也可以用来方便地表示某个范围,比如所有ASCII字符对应的字符组就是【\x00-\x7F],代码
[\x00-\x7F]\准确判断ASCII字符
re.search("^[\x00-\x7F]$","c")!=None # =>True
re.search("^[\xe0-\x7F]$","I")!=None # =>True
re.search("^[\x00-\x7F]$","e")!=None # =>True
re.search("^[\x00-\x7F]$","<")!=None # =>True
元字符与转义
在上面的例子里,字符组中的横线二并不能匹配横线字符,而是用来表示范围,这类字符叫 做元字符(meta-character)字符组的开方括号[、闭方括号]和之前出现的:、§都算元字符。在 匹配中,它们有着特殊的意义。但是,有时候并不需要表示这些特殊意义,只需要表示普通字符 (比如“我就想表示横线字符•”),此时就必须做特殊处理。
先来看字符组中的-,如果它紧邻着字符组中的开方括号[,那么它就是普通字符,其他情况 下都是元字符;而对于其他元字符,取消特殊含义的做法都是转义,也就是在正则表达式中的元 字符之前加上反斜线字符
如果要在字符组内部使用横线二,最好的办法是将它排列在字符组的最开头。[-09]就是包 含三个字符*-*、0、*9的字符组:[0-9]是包含。0〜9这10个字符的字符组,[-0-9]则是由“-”范 围表示法”0-9和横线二共同组成的字符组,它可以匹配11个字符
位置不同含义不同
- 位置产生的含义
#作为普通字符
re.search("[-09]$","3")!=None #=>False
re.search("[-09]$","-")!=None #=>True
#作为元字符
re.search("[-9]$","3")!=None #=>True
re.search("[0-9]$","-")!=None #=>False
#转义之后作为普通字符
re.search("[\-9]$","3")!=None #=>False
re.search("[\-9]$","-")!=None #=>True
仔细观察会发现,在正文里说“在正则表达式中的元字符之前加上反斜线字符\”,而在代码 里写的却不是[0-9],而是[0\-9]这并不是输入错误。
因为在这段程序里,正则表达式是以字符串(String)的方式I提供的,而字符串本身也有关 于转义的规定(你或许记得,在字符串中有\n> \t之类的转义序列)。上面说的“正则表达式”, 其实是经过“字符串转义处理”之后的字符串的值,正则表达式[0-9]包含6个字符:[、0、\、 -、9、],在字符串中表达这6个字符;但是在源代码里,必须使用7个字符: \需要转义成\, 因为处理字符串时,反斜线和之后的字符会被认为是转义序列(Escape Sequence),比如\n> \t 都是合法的转义序列,然而\-不是。
这个问题确实有点麻烦。正则表达式是用来处理字符串的,但它又不完全等于字符串,正则 表达式中的每个反斜线字符、在字符串中(也就是正则表达式之外)还必须转义为\。所以之 前所说的是“正则表达式[0\-9]”,程序里写的却是[0\\-9],这确实有点麻烦。
不过,Python提供了原生字符串(Raw String),它非常适合于正则表达式:正则表达式是怎 样,原生字符串就是怎样,完全不需要考虑正则表达式之外的转义(只有双引号字符是例外,原生字符串内的双引号字符必须转义写成\")。原生字符串的形式是 r”string”也就是在普通字符串之前添加r
]位置产生的含义
#未转义的]
re.search(r"[012]345]$","2345")!=None #=>True
re.search(r"[12]345]$","5")!=None #=>False
re.search(r"[012]345]$","]")!=None #=>False
#转义的]
re.search(r"^[812\]345]$","2345")!=None #=>False
re.search(r"[912\]345]$","5")!=None #=>True
re.search(r"[012\]345]$","]")!None #=>True
除去字符组内部的-,其他元字符的转义都必须在字符之前添加反斜线,[的转义也是如此。 如果只希望匹配字符串[012],直接使用正则表达式[012]是不行的,因为这会被识别为一个字 符组,它只能匹配0、1、2这三个字符中的任意一个;而必须转义,把正则表达式写作[012], 请注意,只有开方括号[需要转义,闭方括号]不需要转义
取消其他元字符的特殊含义
re.search(r"[012]345]$","3")!=None #=False
re.search(r"[012\\]345]$","3")!=None #=>True
re.search(r"[012]$","[012]")!None #=>False
re.search(r"\[012]$","[012]")!=None#=>True
原生字符串的使用
#原生字符串和字符串的等价
r"^[0\-9]$"="^[0\\-9]$" #=True
#原生字符串的转义要简单许多
re.search(r"[\-9]$","3")!=None #=>False
re.search(r"[\-9]$","-")!None #=True
排除型字符数组
在方括号B中列出希望匹配的所有字符,这种字符组叫做“普通字符组”,它的确非常方 便。不过,也有些问题是普通字符组不能解决的。
给定一个由两个字符构成的字符串str,要判断这两个字符是否都是数字字符,可以用 [0-9] [0-9]来匹配。但是,如果要求判断的是这样的字符串——第一个字符不是数字字符,第 二个字符才是数字字符(比如A8、x6) ——应当如何办?数字字符的匹配很好处理,用[0-9]排除型字符组(Negated Character Class)非常类似普通字符组B,只是在开方[之后紧跟一个脱字符^,写作[^……]就表示0-9之外的字符,表示“在当前位置,匹配一个没有列岀的字符”。所以[^0-9]“。0〜9之外的字符”,也就是“非数字字符”。那么,L0-9] [0-9]就可以解决问题了
排除型字符组必须匹配一个字符
除了开方括号[之后的^排除型字符组的用法与普通字符组几乎完全相同,唯一需要改动的 是:在排除型字符组中,如果需要表示横线字符-(而不是用于“-范围表示法”),那么-应该紧跟 在^之后;而在普通字符组中,作为普通字符的横线-应该紧跟在开方括号之后
re.search(r"A[A0-9][0-9]$", "8") != None # => True
re.search(r"A[A0-9][0-9]$", ”A8“)!= None # => True
ASCII对照表
ASCII值 | 控制字符 | ASCII值 | 控制字符 | ASCII值 | 控制字符 | ASCII值 | 控制字符 |
---|---|---|---|---|---|---|---|
0 | NUL | 32 | (space) | 64 | @ | 96 | 、 |
1 | SOH | 33 | ! | 65 | A | 97 | a |
2 | STX | 34 | ” | 66 | B | 98 | b |
3 | ETX | 35 | # | 67 | C | 99 | c |
4 | EOT | 36 | $ | 68 | D | 100 | d |
5 | ENQ | 37 | % | 69 | E | 101 | e |
6 | ACK | 38 | & | 70 | F | 102 | f |
7 | BEL | 39 | ’ | 71 | G | 103 | g |
8 | BS | 40 | ( | 72 | H | 104 | h |
9 | HT | 41 | ) | 73 | I | 105 | i |
10 | LF | 42 | * | 74 | J | 106 | j |
11 | VT | 43 | + | 75 | K | 107 | k |
12 | FF | 44 | , | 76 | L | 108 | l |
13 | CR | 45 | - | 77 | M | 109 | m |
14 | SO | 46 | . | 78 | N | 110 | n |
15 | SI | 47 | / | 79 | O | 111 | o |
16 | DLE | 48 | 0 | 80 | P | 112 | p |
17 | DCI | 49 | 1 | 81 | Q | 113 | q |
18 | DC2 | 50 | 2 | 82 | R | 114 | r |
19 | DC3 | 51 | 3 | 83 | X | 115 | s |
20 | DC4 | 52 | 4 | 84 | T | 116 | t |
21 | NAK | 53 | 5 | 85 | U | 117 | u |
22 | SYN | 54 | 6 | 86 | V | 118 | v |
23 | TB | 55 | 7 | 87 | W | 119 | w |
24 | CAN | 56 | 8 | 88 | X | 120 | x |
25 | EM | 57 | 9 | 89 | Y | 121 | y |
26 | SUB | 58 | : | 90 | Z | 122 | z |
27 | ESC | 59 | ; | 91 | [ | 123 | { |
28 | FS | 60 | < | 92 | \ | 124 | | |
29 | GS | 61 | = | 93 | ] | 125 | } |
30 | RS | 62 | > | 94 | ^ | 126 | ~ |
31 | US | 63 | ? | 95 | — | 127 | DEL |