Groovy正则表达式
正则表达式是一种方便地用于检索字符串中特定文本的强有力工具,在编程中非常常见。Groovy中,正则表达式的使用更是得心应手。在本文中,我们将会学习Groovy中正则表达式的使用方法,并且将介绍基本的正则表达式语法和Groovy中方法的实现。
正则表达式的语法
字符串字面量
在Groovy中,字符串字面量可以通过单引号或双引号表示。以下是两种表示方法的示例:
def name1 = 'Tom'
def name2 = "Jerry"
这两个示例中,name1
和name2
均为字符串类型,值分别为’Tom’和’Jerry’。这两种表示方式在Groovy中并没有本质上的区别,都被认为是普通字符串。
字符类
字符类是由方括号[]
来表示的。在方括号中,可以任意指定想要匹配的字符。例如,方括号[aeiou]
表示任意一个元音字母。
assert 'apple'.matches('[aeiou].*')
上面的代码中,使用matches
方法判断’apple’是否以元音字母开头,由于’a’是元音字母,因此assert
语句会通过。
除了指定单个字符外,可以通过连字符-
来指定一个字符范围。例如,方括号[0-9]
表示任意一个数字字符。
assert '12345'.matches('[0-9]{5}')
上面的代码中,使用matches
方法判断’12345’是否由五个数字字符组成,由于符合规则,因此assert
语句会通过。
特殊字符类
特殊字符类是一些常用的字符类的简写形式。
字符类 | 等价于 |
---|---|
\d |
[0-9] |
\D |
[^0-9] |
\s |
[ \t\r\n\f] |
\S |
[^ \t\r\n\f] |
\w |
[a-zA-Z_0-9] |
\W |
[^a-zA-Z_0-9] |
例如,\d
表示任意一个数字字符,\s
表示任意一个空白字符。
assert '1 2 3'.replaceAll('\s', '') == '123'
上面的代码中,使用replaceAll
方法将’1 2 3’字符串中的所有空白字符都替换为空白字符串,因此得到的结果是’123’。
重复匹配
在正则表达式中,可以使用*
、+
、?
以及花括号{}
来表示重复匹配。
符号 | 说明 |
---|---|
* |
匹配前一个字符0或多次 |
+ |
匹配前一个字符1或多次 |
? |
匹配前一个字符0或1次 |
{n} |
匹配前一个字符恰好n次 |
{n,} |
匹配前一个字符至少n次 |
{n,m} |
匹配前一个字符至少n次,但不能超过m次 |
例如,a*
表示匹配任意数量的’a’,a+
表示匹配至少一个’a’,a?
表示匹配0或1个’a’,a{3}
表示恰好匹配3个’a’,a{3,}
表示匹配至少3个’a’,a{3,5}
表示匹配3至5个’a’。
assert 'aaaab'.replaceAll('a+', 'c') == 'cb'
上面的代码中,使用replaceAll
方法将’aaaab’字符串中的所有连续的’a’字符都替换为’c’,因此得到的结果是’cb’。
选择匹配
在正则表达式中,可以使用竖线|
来表示选择匹配。
assert 'hello world' ==~ /hello|world/
上面的代码中,使用=~
运算符判断’hello world’是否匹配正则表达式/hello|world/,由于其中的’hello’部分与字符串中匹配,因此assert
语句会通过。
分组
在正则表达式中,可以使用括号()
来表示分组。分组允许对多个字符进行操作,例如应用重复匹配和选择匹配等。
assert 'abababa' ==~ /(ab)+/
上面的代码中,使用=~
运算符判断’abababa’是否匹配正则表达式/(ab)+/,其中括号内的分组表示匹配至少一个’ab’。由于字符串中满足至少一个’ab’的条件,因此assert
语句会通过。
零宽度断言
在正则表达式中,有些特殊的字符不参与匹配,但可以帮助我们更精确地定义匹配模式。这些特殊字符被称为零宽度断言。
正向零宽度断言
正向零宽度断言使用类似于括号的语法,以(?=
开头,以)
结尾,并在括号中放置一个子表达式。该子表达式在匹配中并不参与捕获,但必须出现在指定位置。
def str = "Java 8"
assert str.find(/(?=\d)\d/) == "8"
上面的代码中,将字符串”Java 8″放到find
方法中,查找出它包含的数字字符。由于’8’字符前面有一个数字字符,因此正向零宽度断言能够精确地定位到’8’字符,并将其返回。
负向零宽度断言
负向零宽度断言与正向零宽度断言类似,但在正向零宽度断言之前加上?!
前缀。
def str = "abacadaeaf"
assert str.replaceAll(/.(?<!a)/, "#") == "a#a#a#a#a#"
上面的代码中,使用replaceAll
方法将字符串”abacadaeaf”中除了以’a’开头的字符外的所有字符都替换为’#’,例如’b’、’c’、’d’、’e’、’f’都会被替换掉。 负向零宽度断言.(?<!a)
表示匹配除以’a’开头的字符外的任意一个字符,并将其用’#’替换。
Groovy中的正则表达式方法
Groovy提供了多种正则表达式方法,方便开发者进行各种操作。
find
find
方法可以在字符串中查找第一个匹配正则表达式的子串,返回匹配的字符串。
def str = 'The quick brown fox jumps over the lazy dog.'
def pattern = /\wo\w/
assert str.find(pattern) == 'brown'
上面的代码中,定义了一个字符串和一个正则表达式,并使用find
方法在字符串中查找第一个匹配正则表达式的子串,得到的结果是’brown’。
findAll
findAll
方法会在字符串中查找所有匹配正则表达式的子串,返回匹配的字符串组成的列表。
def str = "张三:25岁;李四:30岁;王五:29岁;赵六:27岁"
def pattern = /\D+(\d+)\D+/
assert str.findAll(pattern).collect{it[1]}.sum() == 111
上面的代码中,定义了一个字符串和一个正则表达式,并使用findAll
方法在字符串中查找所有匹配正则表达式的子串,得到的结果是一个字符串列表,列表中的每个字符串都匹配了一个年龄数字字符。使用collect
方法过滤出所有的数字字符并使用sum
方法计算它们的和,得到的结果是111。
findAllMatches
findAllMatches
方法与findAll
类似,但返回的是一个匹配对象(Match)。匹配对象包含了匹配的字符串和所在位置等信息。
def str = 'The quick brown fox jumps over the lazy dog.'
def pattern = /\w+/
def matches = str.findAllMatches(pattern)
assert matches[1].group() == 'quick'
上面的代码中,定义了一个字符串和一个正则表达式,并使用findAllMatches
方法查找所有匹配正则表达式的子串,得到的结果是一个匹配对象的列表。使用group
方法获取列表中第二个匹配对象中的字符串。
replaceAll
replaceAll
方法可以用指定的字符串将所有匹配正则表达式的子串都替换掉。
def str = 'The quick brown fox jumps over the lazy dog.'
def pattern = /[aeiou]/
assert str.replaceAll(pattern, '*') == 'Th* q**ck br*wn f*x j*mps *v*r th* l*zy d*g.'
上面的代码中,定义了一个字符串和一个正则表达式,并使用replaceAll
方法将字符串中所有匹配正则表达式的元音字母都替换为’*’字符。
split
split
方法可以将指定字符串按照正则表达式进行拆分,返回拆分后的字符串数组。
def str = 'The quick brown fox jumps over the lazy dog.'
def pattern = /\W+/
assert str.split(pattern) == ['The', 'quick', 'brown', 'fox', 'jumps', 'over', 'the', 'lazy', 'dog', '']
上面的代码中,定义了一个字符串和一个正则表达式,并使用split
方法将字符串按照正则表达式进行拆分,得到的结果是一个字符串数组。注意到尾部会多出一个空字符串,这是由于分隔符在字符串结尾的原因。