Loading... 正则表达式是匹配模式,要么匹配字符,要么匹配位置。 本章内容包括: 1. 两种模糊匹配 2. 字符组 3. 量词 4. 分支结构 5. 案例分析 ##### 1. 两种模糊匹配 > 如果正则只有精确匹配是没有多大意义的,比如/hello/,也只能匹配字符串中的“hello”字符串。 ```java String content = "hello"; String pattern = "hello"; // Java中表达正则表达式都是全局匹配不包含首尾// System.out.println(ReUtil.isMatch(pattern, content)); // => true ``` 正则表达式之所以强大,是因为其能实现模糊匹配。 而模糊匹配,有两个方向上的“模糊”:横向模糊和纵向模糊。 ###### 1.1 横向模糊匹配 <div class="tip inlineBlock info"> 横向模糊匹配指的是:一个正则可匹配的字符串的长度不是固定的,可以是多种情况的。 </div> 其实现的方式使用量词。譬如:{m,n},表示连续出现至少m次,最多n次。 比如:`/ab{2,5}c/` 表示匹配这样一个字符串:第一个字符是“a”,接下来是2到5个字符“b”,最后是字符“c”。测试如下: ```java String content = "abc abbc abbbc abbbbc abbbbbc abbbbbbc"; String pattern = "ab{2,5}c"; List<String> resultFindAll = ReUtil.findAll(pattern, content, 0, new ArrayList<String>()); System.out.println(resultFindAll); // => [abbc, abbbc, abbbbc, abbbbbc] ``` ###### 1.2 纵向模糊匹配 <div class="tip inlineBlock info"> 纵向模糊指的是,一个正则匹配的字符串,具体到某一位字符时,它可以不是某个确定的字符,可以有多种可能。 </div> 其实现的方式是使用字符组。譬如`[abc]`,表示该字符是可以字符“a”、“b”、“c”中的任何一个。 比如`/a[123]c/`可以匹配如下三种字符串:"a1c"、"a2c"、"a3c"。测试如下: ```java String content = "a1c a2c a3c a4c a5c a6c"; String pattern = "a[123]c"; List<String> resultFindAll = ReUtil.findAll(pattern, content, 0, new ArrayList<String>()); System.out.println(resultFindAll); // => [a1c, a2c, a3c] ``` ##### 2. 字符组 > 需要强调的是,虽叫字符组(字符类),但只是其中一个字符。例如`[abc]`,表示匹配一个字符,它可以是“a”、“b”、“c”之一。 ###### 2.1 范围表示法 比如`[123456abcdefGHIJKLM]`,可以写成`[1-6a-fG-M]`。用连字符`-`来省略和简写。 因为连字符有特殊用途,那么要匹配“a”、“-”、“z”这三者中任意一个字符,该怎么做呢? 不能写成`[a-z]`,因为其表示小写字符中的任何一个字符。 可以写成如下的方式:`[-az]`或`[az-]`或`[a\-z]`。即要么放在开头,要么放在结尾,要么转义。总之不会让引擎认为是范围表示法就行了。 ###### 2.2 排除字符组 纵向模糊匹配,还有一种情形就是,某位字符可以是任何东西,但就不能是"a"、"b"、"c"。 此时就是排除字符组(反义字符组)的概念。例如`[^abc]`,表示是一个除"a"、"b"、"c"之外的任意一个字符。字符组的第一位放`^`(脱字符),表示求反的概念。 ###### 2.3 常见的简写形式 有了字符组的概念后,一些常见的符号我们也就理解了。因为它们都是系统自带的简写形式。 > **`\d`** 就是`[0-9]`。表示是一位数字。记忆方式:其英文是digit(数字)。 > > **`\D`** 就是`[^0-9]`。表示除数字外的任意字符。 > > **`\w`** 就是`[0-9a-zA-Z_]`。表示数字、大小写字母和下划线。记忆方式:w是word的简写,也称单词字符。 > > **`\W`** 是`[^0-9a-zA-Z_]`。非单词字符。 > > **`\s`** 是`[ \t\v\n\r\f]`。表示空白符,包括空格、水平制表符、垂直制表符、换行符、回车符、换页符。 > > **`\S`** 是`[^ \t\v\n\r\f]`。 非空白符。 > > **`.`** 就是`[^\n\r\u2028\u2029]`。通配符,表示几乎任意字符。换行符、回车符、行分隔符和段分隔符除外。 ##### 3. 量词 量词也称重复。掌握`{m,n}`的准确含义后,只需要记住一些简写形式。 ###### 3.1 简写形式 > `{m,}` 表示至少出现m次。 > > `{m}` 等价于`{m,m}`,表示出现m次。 > > `?` 等价于`{0,1}`,表示出现或者不出现。 > > `+ `等价于`{1,}`,表示出现至少一次。 > > `*` 等价于`{0,}`,表示出现任意次,有可能不出现。 ###### 3.2 贪婪匹配和惰性匹配 看如下例子: ```java String content = "21 1231 232131 2131 213 213112"; // 表示数字连续出现2到5次。会匹配2位、3位、4位、5位连续数字。 String pattern = "\\d{2,5}"; List<String> resultFindAll = ReUtil.findAll(pattern, content, 0, new ArrayList<String>()); System.out.println(resultFindAll); // => [21, 1231, 23213, 2131, 213, 21311] ``` 该正则表达式是贪婪的:它会尽可能多的匹配。你能给我6个,我就要5个。你能给我3个,我就3要个。反正只要在能力范围内,越多越好。 > 而惰性匹配,就是尽可能少的匹配 ```java String content = "21 1231 232131 2131 213 213112"; String pattern = "\\d{2,5}?"; // => [21, 12, 31, 23, 21, 31, 21, 31, 21, 21, 31, 12] ``` 其中`/\d{2,5}?/`表示,虽然2到5次都行,当2个就够的时候,就不在往下尝试了。 通过在量词后面加个问号就能实现惰性匹配,因此所有惰性匹配情形如下: > `{m,n}?` > `{m,}?` > `+?` > `*?` ##### 4. 多选分支 > 一个模式可以实现横向和纵向模糊匹配。而多选分支可以支持多个子模式任选其一。 具体形式如下:`(p1|p2|p3)`,其中`p1`、`p2`和`p3`是子模式,用`|`(管道符)分隔,表示其中任何之一。 <div class="tip inlineBlock warning"> 分支结构也是惰性的,即当前面的匹配上了,后面的就不再尝试了。 </div> ##### 5. 案例分析 ###### 5.1 匹配16进制颜色值 <span style='color:#DC143C'>要求匹配:</span> > #ffbbad > > #Fc01DF > > #FFF > > #ffE 分析: 表示一个16进制字符,可以用字符组`[0-9a-fA-F]`。 其中字符可以出现3或6次,需要是用量词和分支结构。 使用分支结构时,需要注意顺序。 正则如下: ```java String content = "#asaasa #Fc01DF #FFF #ffE"; String pattern = "#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})"; // => [#Fc01DF, #FFF, #ffE] ``` ###### 5.2 匹配时间 > 23:59 > > 07:12 分析: 共4位数字,第一位数字可以为`[0-2]`。 当第1位为2时,第2位可以为`[0-3]`,其他情况时,第2位为`[0-9]`。 第3位数字为`[0-5]`,第4位为`[0-9]` 正则如下: ```java String content = "12:59"; String pattern = "([01][0-9]|[2][0-3]):[0-5][0-9]$"; // => [12:59] ``` 如果也要求匹配7:9,也就是说时分前面的0可以省略,该怎么写正则呢? 正则如下: <div class="hideContent">此处内容需要评论回复后(审核通过)方可阅读。</div> ###### 5.3 匹配日期 <div class="hideContent">此处内容需要评论回复后(审核通过)方可阅读。</div> 学到这里 算是对正则入门了! 最后修改:2021 年 10 月 20 日 © 来自互联网 打赏 赞赏作者 支付宝微信 赞 社会很单纯~复杂滴是人呐~谁能在乎我呀