简介
正则表达式是对字符串执行模式匹配的技术
正则表达式:regular expression 简称: RegExp
正则表达式的语法
如果要想灵活的运用正则表达式,必须了解其中各种元字符的功能,元字符从功能上大致分为:
- 限定符
- 选择匹配符
- 分组组合和反向引用符
- 特殊字符
- 字符匹配符
- 定位符
元字符
转义号 \\
符号说明:在我们使用正则表达式去检索某些特殊字符的时候,需要用到转义符号,否则检索不到结果,甚至会报错的。案例:用$去匹配“abc$(”会怎样?
用(去匹配”abc$(”会怎样?
再次提示:
在Java的正则表达式中,两个 \\ 代表其他语言中的一个 /
需要用到转义符号的字符有以下:. * + () $ / \ ? [] ^ {}
字符匹配符
符号 | 符号 | 实例 | 解释 | 匹配输入 |
---|
[ ] | 可接收的字符列表 | [ajkh] | a、j、k、h、中任意一个字符 | q |
[ ^ ] | 不接收的字符列表 | [^abc] | 除a、b、c、之外的任意一个字符,包含数字和特殊符号 | d |
- | 连字符 | a-z | 任意单个小写字母 | d |
. | 匹配除\n以外的任何字符 | a..b | 以a开头,以b结尾,中间包括2个任意字符的长度为4的字符串 | aaab |
\\d | 匹配单个数字字符,相当于[0-9] | \\d{3}(\\d)? | 包括3个或4个数字的字符串 | 123、2313 |
\\D | 匹配单个非数字字符,相当于[^0-9] | \\D(\\d)* | 以单个非数字字符开头,后接任意个数字符串 | a、A24 |
\\w | 匹配单个数字、大小写字母字符、下划线,相当于[0-9a-zA-Z_] | \\d{3}\\w{4} | 以3个数字字符开头的长度为7的数字字母字符串 | 123sad2 |
\\W | 匹配单个非数字、大小写字母字符,相当于[^0-9a-zA-Z_] | \\W+\\d{2} | 以至少1个非数字字母字符开头,2个数字字符结尾的字符串 | #28、@sdfq12 |
java正则表达式默认是区分字母大小写的,如何实现不区分大小写
- (?i)abc表示abc都不区分大小写
- a(?i)bc表示bc不区分大小写
- a((?i)b)c表示只有b不区分大小写
- Pattern pat = Pattern.compile(regEx,Pattern.CASE_INSENSITIVE)
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| public class Regexp02 { public static void main(String[] args) { String content = "a1.1c8s.abc ABC_@";
String regexp = ".";
Pattern pattern = Pattern.compile(regexp);
Matcher matcher = pattern.matcher(content); while (matcher.find()) { System.out.print("结果:" + matcher.group(0) + " "); } } }
|
选择匹配符
在匹配某个字符串的时候是选择性的,即:既可以匹配这个,又可以匹配那个,这时你需要用到 选择匹配符 |
符号 | 符号 | 示例 | 解释 |
---|
| | 匹配 “|” 之前或之后的表达式 | ab|cd | ab或者cd |
例子:
| public class Regexp03 { public static void main(String[] args) {
String content = "sdfhqwhqwe12411"; String regexp = "sd|24"; Pattern pattern = Pattern.compile(regexp); Matcher matcher = pattern.matcher(content); while (matcher.find()) { System.out.println("结果是:" + matcher.group(0)); } } }
|
限定符
用于指定其前面的字符和组合项连续出现多少次
符号 | 含义 | 示例 | 说明 | 匹配输入 |
---|
* | 指定字符重复0次或n次(无要求) | (abc)* | 仅包含任意个abc的字符串,等效于\w* | abc、abcabcabc |
+ | 指定字符重复1次或n次(至少1次) | m+(abc)* | 以至少1个m开头,后接任意个abc的字符串 | m、mabc |
? | 指定字符重复0次或1次(最多1次) | m+abc? | 以至少1个m开头,后接ab或abc的字符串 | acb、mmab |
{n} | 只能输入n个字符 | [abcd]{3} | 由abcd中字母组成的任意长度为3的字符串 | abc、dbc、adc |
{n,} | 指定至少n个匹配 | [abcd]{3,} | 由abcd中字母组成的任意长度不小于3的字符串 | aab、dbc、aaabdc |
{n,m} | 指定至少n个但不多于m个匹配 | [abcd]{3,5} | 由abcd中字母组成的任意长度不小于3,不大于5的字符串 | abc、abcd、aaaaa、bcdab |
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public class Regexp04 { public static void main(String[] args) {
String content = "411111111a1aaaaahello,world";
String regexp = "a1?";
Pattern pattern = Pattern.compile(regexp); Matcher matcher = pattern.matcher(content); while (matcher.find()) { System.out.println("结果--> " + matcher.group(0)); } } }
|
定位符
定位符,规定要匹配的字符串出现的位置,比如在字符串的开始还是在结束的位置,这个也是相当有用的。
符号 | 含义 | 示例 | 说明 | 匹配输入 |
---|
^ | 指定起始字符 | ^[0-9]+[a-z]* | 以至少1个数字开头,后接任意个小写字母的字符串 | 123、6aa |
$ | 指定结束字符 | ^[0-9]\-[a-z]+$ | 以1个数字开头后接连字符 “-“,并以至少1个小写字母结尾的字符串 | 1-a |
\\b | 匹配目标字符串的边界 | han\\b | 这里说的字符串的边界指的是字串间有空格,或者是目标字符串的结束位置 | hanshunping、sphan nnhan |
\\B | 匹配目标字符串的非边界 | han\\B | 和\\b的含义相反 | hanshunping |
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class Regexp05 { public static void main(String[] args) {
String content = "hellojinanc aahello";
String regexp = "hello\\B";
Pattern pattern = Pattern.compile(regexp); Matcher matcher = pattern.matcher(content); while (matcher.find()) { System.out.println(matcher.group(0)); } } }
|
分组
常用分组
常用分组构造形式 | 说明 |
---|
(pattern) | 非命名捕获。捕获匹配的子字符串。编号为零的第一个捕获是由整个正则表达式模式匹配的文本,其他捕获结果则根据左括号的顺序从1开始自动编号 |
(?pattern) | 命名捕获。将匹配的子字符串捕获到一个组名称或编号名称中。用于name的字符串不能包含任何标点符号,并且不能以数字开头。可以使用单引号替代尖括号,例如(?’name’) |
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class Regexp06 { public static void main(String[] args) {
String content = "helloworld hello 98763432";
String regexp = "(?<c1>\\d\\d)(?<c2>\\d\\d)"; Pattern pattern = Pattern.compile(regexp); Matcher matcher = pattern.matcher(content); while (matcher.find()) { System.out.println("结果为:" + matcher.group(0)); System.out.println("第一组:" + matcher.group(1)); System.out.println("通过分组名称取值:" + matcher.group("c1")); System.out.println("第二组:" + matcher.group(2)); System.out.println("通过分组名称取值:" + matcher.group("c2")); } } }
|
特别分组
常用分组构造形式 | 说明 |
---|
(?:pattern) | 匹配 pattern但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于用”or”字符(组合模式部件的情况很有用。例如,”industr(?:y[lies)是比’industrylindustries’更经济的表达式。 |
(?=pattern) | 它是一个非捕获匹配。例如,”Windows (?=95[98[NT[2000)’匹配”Windows 2000”中的”Windows”,但不匹配”Windows 3.1”中的”windows”。 |
(?!pattern) | 该表达式匹配不处于匹配pattern 的字符串的起始点的搜索字符串。它提是一个非捕获匹配。例如,”Windows (?!95]98[NT[2000)’匹配 “Windows 3.1”中的“Windows”,但不匹配”Windows 2000”中的”Windows”。 |
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| public class Regexp07 { public static void main(String[] args) { String content = "hello仅安小课堂 Jack仅安老师 仅安同学hello";
String regexp = "仅安(?!小课堂|老师)";
Pattern pattern = Pattern.compile(regexp); Matcher matcher = pattern.matcher(content); while (matcher.find()) { System.out.println(matcher.group(0)); } } }
|
应用实例
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| public class Regexp09 { public static void main(String[] args) {
String content = "15147123242"; String regexp = "^1[3|4|5|8]\\d{9}$";
Pattern pattern = Pattern.compile(regexp); Matcher matcher = pattern.matcher(content); if (matcher.find()) { System.out.println("满足条件,结果为: " + matcher.group(0)); } else { System.out.println("不满足条件"); } } }
|
验证 URL,较为复杂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class Regexp10 { public static void main(String[] args) {
String content = "https://www.bilibili.com/video/BV1Eq4y1E79W?p=17&spm_id_from=pageDriver";
String regexp = "^((https|http)://)?([\\w-]+\\.)+[\\w-]+(\\/[\\w-?=%&#/.]*)?$";
Pattern pattern = Pattern.compile(regexp); Matcher matcher = pattern.matcher(content); if (matcher.find()) { System.out.println("满足条件,结果为: " + matcher.group(0)); } else { System.out.println("不满足条件"); } } }
|
三个常用类
Pattern 、Matcher、PatternSyntaxException
Pattern类
pattern对象是一个正则表达式对象。Pattern 类没有公共构造方法。要创建一个 Pattern对象,调用其公共静态方法,它返回一个 Pattern对象。该方法接受一个正则表达式作为它的第一个参数,比如:Patternr= Pattern.compile(pattern);
| public class PatternMethod { public static void main(String[] args) { String content = "hello hello,world,仅安";
String regexp = "hello.*"; boolean matches = Pattern.matches(regexp, content); System.out.println("整体匹配= " + matches); } }
|
Matcher 类
Matcher对象是对输入字符串进行解释和匹配的引擎。与Pattern类一样, Matcher也没有公共构造方法。你需要调用 Pattern对象的matcher方法来获得一个 Matcher对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class MatcherMethod { public static void main(String[] args) { String content = "hello jinanc world hello jinanc apple xiaomi";
String regexp = "hello";
Pattern pattern = Pattern.compile(regexp); Matcher matcher = pattern.matcher(content); while (matcher.find()) { System.out.println("========"); System.out.println(matcher.start()); System.out.println(matcher.end()); System.out.println("找到:" + content.substring(matcher.start(), matcher.end())); }
System.out.println("整体匹配:" + matcher.matches()); regexp = "jinanc"; pattern = Pattern.compile(regexp); matcher = pattern.matcher(content); String newContent = matcher.replaceAll("仅安"); System.out.println("newContent:" + newContent); }
|
PatternSyntaxException
PatternSyntaxException是一个非强制异常类,它表示一个正则表达式模式中的语法错误。
分组、捕获、反向引用
分组
我们可以用圆括号组成一个比较复杂的匹配模式,那么一个圆括号的部分我们可以看作是一个子表达式/一个分组。
捕获
把正则表达式中子表达式/分组匹配的内容,保存到内存中以数字编号或显式命名的组里,方便后面引用,从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。组0代表的是整个正则式
反向引用
圆括号的内容被捕获后,可以在这个括号后被使用,从而写出一个比较实用的匹配模式,这个我们称为反向引用
,这种引用既可以是在正则表达式内部,也可以是在正则表达式外部,内部反向引用\\分组号
,外部反向引用$分组号
小案例:
- 要匹配两个连续的相同数字
- 要匹配五个连续的相同数字
- 要匹配个位和千位相同,十位和百位相同的数
思考题:
请在字符串中检索商品编号,形式如:12321-333999111这样的号码,要求满足前面是一个五位数,然后一个-号,然后是一个九位数,连续的每三位要相同
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class Regexp11 { public static void main(String[] args) { String content = "hello tom11 hhh22 tom jack33333 ce1331 12321-333999111";
String regexp = "\\d{5}-(\\d)\\1{2}(\\d)\\2{2}(\\d)\\3{2}";
Pattern pattern = Pattern.compile(regexp); Matcher matcher = pattern.matcher(content); while (matcher.find()) { System.out.println(matcher.group(0)); } } }
|
结巴去除案例
把类似:”我….我要….学学学学….编程java!”;
通过正则表达式修改成“我要学编程java”
实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public class Regexp12 { public static void main(String[] args) { String content = "我....我要....学学学学....编程java!";
Pattern pattern = Pattern.compile("\\."); Matcher matcher = pattern.matcher(content); content = matcher.replaceAll(""); System.out.println(content);
pattern = Pattern.compile("(.)\\1+"); matcher = pattern.matcher(content); while (matcher.find()) { System.out.println(matcher.group(0)); } content = matcher.replaceAll("$1"); System.out.println(content);
content = Pattern.compile("(.)\\1+").matcher(content).replaceAll("$1"); System.out.println(content); } }
|
替换分割匹配
在 String类中使用正则表达式
替换功能
| public String replaceAll(String regex, String replacement)
|
例子:
| String content = "2000年5月,JDK1.3、JDK1.4和J2SE1.3相继发布,几周后其获得了Apple公司Mac OS X的工业标准的支持。";
content = content.replaceAll("JDK1\\.[3|4]", "JDK"); System.out.println(content);
|
是否满足某个条件
| public boolean matches(String regex)
|
例子:
| String phone = "13826789291"; if (phone.matches("1(38|39])\\d{8}")) { System.out.println("验证成功"); } else { System.out.println("验证失败"); }
|
分割功能
| public String[] split(String regex)
|
例子:
| String str = "hello#ttabc-jack12smith~北京"; String[] split = str.split("#|-|\\d+|~"); for (String s : split) { System.out.println(s); }
|
几个案例
案例一:
| public class work01 { public static void main(String[] args) {
String content = "2640053707@qq.com"; String regexp = "[\\w-]+@([a-zA-Z]+\\.)+[a-zA-Z]+"; if (content.matches(regexp)) { System.out.println("匹配成功"); } else { System.out.println("匹配失败"); } } }
|
案例二:
| public class work02 { public static void main(String[] args) {
String content = "-0.1313"; String regexp = "^[-+]?([1-9]\\d*|0)(\\.\\d+)?$"; if (content.matches(regexp)) { System.out.println("匹配成功"); } else { System.out.println("匹配失败"); } } }
|
案例三:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class work03 { public static void main(String[] args) {
String content = "https://www.sohu.com:8080/abc/index.htm"; String regexp = "^([a-zA-Z]+)://([a-zA-Z.]+):(\\d+)[\\w-/]*/([\\w.]+)$"; Pattern pattern = Pattern.compile(regexp); Matcher matcher = pattern.matcher(content); if (matcher.matches()) { System.out.println("整体匹配到----> " + matcher.group(0)); System.out.println("协议:" + matcher.group(1)); System.out.println("域名:" + matcher.group(2)); System.out.println("端口:" + matcher.group(3)); System.out.println("文件名:" + matcher.group(4)); } else { System.err.println("匹配失败了..."); } } }
|
一些常用的正则参考
菜鸟工具