正则表达式——普通字符组(续)

正则表达式提供了-范围表示法(range),它更直观,能进一步简化字符组。

所谓"-范围表示法",就是用[x-y]的形式表示x到y整个范围内的字符,省去一一列出的麻烦,这样[0123456789]就可以表示为[0-9]。如果你觉得这不算什么,那么确实比[abcdefghijklmnopqrstuvwxyz]简单太多了。

你可能会问,"-范围表示法"的范围是如何确定的?为什么要写作[0-9],而不写作[9-0]?

要回答这个问题,必须了解范围表示法的实质。在字符组中,-表示的范围,一般是根据字符对应的码值Code Point,也就是字符在对应编码表中的编码的数值)来确定的,码值小的字符在前,码值大的字符在后。在ASCII编码中(包括各种兼容ASCII的编码中),字符0的码值是48(十进制),字符9的码值是57(十进制),所以[0-9]等价于[0123456789];而[9-0]则是错误的范围,因为9的码值大于0,所以会报错。

例1-5  [0-9]是合法的,[9-0]会报错

re.search("^[0-9]$", "2") != None       #  => True  
re.search("^[9-0]$", "2") != None  
Traceback (most recent call last):  
error: bad character range  

 

如果知道0~9的码值是48~57,a~z的码值是97~122,A~Z的码值是65~90,能不能用[0-z]统一表示数字字符、小写字母、大写字母呢?

答案是:勉强可以,但不推荐这么做。根据惯例,字符组的范围表示法都表示一类字符(数字字符是一类,字母字符也是一类),所以虽然[0-9]、[a-z]都是很好理解的,但[0-z]却很难理解,不熟悉ASCII编码表的人甚至不知道这个字符组还能匹配大写字母,更何况,在码值48到122之间,除去数字字符(码值48~57)、小写字母(码值97~122)、大写字母(码值65~90),还有不少标点符号(参见表1-1),从字符组[0-z]中却很难看出来,使用时就容易引起误会,例1-6所示的程序就很可能让人莫名其妙。

表1-1  ASCII编码表(片段)

码值

字符

码值

字符

码值

字符

码值

字符

码值

字符

48

0

63

?

78

N

93

]

108

l

49

1

64

@

79

O

94

^

109

m

50

2

65

A

80

P

95

_

110

n

51

3

66

B

81

Q

96

`

111

o

52

4

67

C

82

R

97

a

112

p

53

5

68

D

83

S

98

b

113

q

54

6

69

E

84

T

99

c

114

r

55

7

70

F

85

U

100

d

115

s

56

8

71

G

86

V

101

e

116

t

57

9

72

H

87

W

102

f

117

u

58

:

73

I

88

X

103

g

118

v

59

;

74

J

89

Y

104

h

119

w

60

75

K

90

Z

105

i

120

x

61

=

76

L

91

[

106

j

121

y

62

77

M

92

\

107

k

122

z

 

例1-6  [0-z] 的奇怪匹配

re.search("^[0-z]$", "A") != None # => True 

re.search("^[0-z]$", ":") != None # => True 

 在字符组中可以同时并列多个"-范围表示法",字符组[0-9a-zA-Z]可以匹配数字、大写字母或小写字母;字符组 [0-9a-fA-F]可以匹配数字,大、小写形式的a~f,它可以用来验证十六进制字符,代码见例1-7

例1-7  [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]$", "G") != None  #  => False  

 

在不少语言中,还可以用转义序列\xhex来表示一个字符,其中\x是固定前缀,表示转义序列的开头,num是字符对应的码值(Code Point,详见第127页,下文用?127表示),是一个两位的十六进制数值。比如字符A的码值是41(十进制则为65),所以也可以用\x41表示。

字符组中有时会出现这种表示法,它可以表现一些难以输入或者难以显示的字符,比如\x7F;也可以用来方便地表示某个范围,比如所有ASCII字符对应的字符组就是[\x00-\x7F],代码见例1-8。这种表示法很重要,在第120页还会讲到它,依靠这种表示法可以很方便地匹配所有的中文字符。

例1-8  [\x00-\x7F]准确判断ASCII字符

re.search("^[\x00-\x7F]$", "c") != None  #  => True  
re.search("^[\x00-\x7F]$", "I") != None  #  => True  
re.search("^[\x00-\x7F]$", "0") != None  #  => True  
re.search("^[\x00-\x7F]$", "<") != None  #  => True  

 

posted @ 2018-10-19 10:03  gaara724  阅读(232)  评论(0编辑  收藏  举报