09-Java常用类补充:正则表达式

09—Java常用类补充:正则表达式

1. 底层实现

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
package com.xiongzhuo.regexp;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* 分析java的正则表达式的底层实现(重要)
*/
public class RegTheory {
public static void main(String[] args) {

String content = "1998年12月8日,第二代Java平台的企业版J2EE发布。1999年6月,Sun公司发布了" +
"第二代Java平台(简称为Java2)的3个版本:J2ME(Java2 Micro Edition,Java2平台的微型" +
"版),应用于移动、无线及有限资源的环境;J2SE(Java 2 Standard Edition,Java 2平台的" +
"标准版),应用于桌面环境;J2EE(Java 2Enterprise Edition,Java 2平台的企业版),应" +
"用3443于基于Java的应用服务器。Java 2平台的发布,是Java发展过程中最重要的一个" +
"里程碑,标志着Java的应用开始普及9889 ";
//目标:匹配所有四个数字
//说明
//1. \\d 表示一个任意的数字
String regStr = "(\\d\\d)(\\d\\d)";
//2. 创建模式对象[即正则表达式对象]
Pattern pattern = Pattern.compile(regStr);
//3. 创建匹配器
//说明:创建匹配器matcher, 按照 正则表达式的规则 去匹配 content字符串
Matcher matcher = pattern.matcher(content);

//4.开始匹配
/**
*
* matcher.find() 完成的任务 (考虑分组)
* 什么是分组,比如 (\d\d)(\d\d) ,正则表达式中有() 表示分组,第1个()表示第1组,第2个()表示第2组...
* 1. 根据指定的规则 ,定位满足规则的子字符串(比如(19)(98))
* 2. 找到后,将 子字符串的开始的索引记录到 matcher对象的属性 int[] groups;
* 2.1 groups[0] = 0 , 把该子字符串的结束的索引+1的值记录到 groups[1] = 4
* 2.2 记录1组()匹配到的字符串 groups[2] = 0 groups[3] = 2
* 2.3 记录2组()匹配到的字符串 groups[4] = 2 groups[5] = 4
* 2.4.如果有更多的分组.....
* 3. 同时记录oldLast 的值为 子字符串的结束的 索引+1的值即35, 即下次执行find时,就从35开始匹配
*
* matcher.group(0) 分析
*
* 源码:
* public String group(int group) {
* if (first < 0)
* throw new IllegalStateException("No match found");
* if (group < 0 || group > groupCount())
* throw new IndexOutOfBoundsException("No group " + group);
* if ((groups[group*2] == -1) || (groups[group*2+1] == -1))
* return null;
* return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
* }
*
*CharSequence getSubSequence(int beginIndex, int endIndex) {
* return text.subSequence(beginIndex, endIndex);
* }
* CharSequence text;//The original string being matched.
* 1. 根据 groups[0]=31 和 groups[1]=35 的记录的位置,从content开始截取子字符串返回
* 就是 [31,35) 包含 31 但是不包含索引为 35的位置
*
* 如果再次指向 find方法.仍然安上面分析来执行
*/
while (matcher.find()) {
//小结
//1. 如果正则表达式有() 即分组
//2. 取出匹配的字符串规则如下
//3. group(0) 表示匹配到的子字符串
//4. group(1) 表示匹配到的子字符串的第一组字串
//5. group(2) 表示匹配到的子字符串的第2组字串
//6. ... 但是分组的数不能越界.
System.out.println("找到: " + matcher.group(0));
System.out.println("第1组()匹配到的值=" + matcher.group(1));
System.out.println("第2组()匹配到的值=" + matcher.group(2));


}
}
}

找到: 1998
第1组()匹配到的值=19
第2组()匹配到的值=98
找到: 1999
第1组()匹配到的值=19
第2组()匹配到的值=99
找到: 3443
第1组()匹配到的值=34
第2组()匹配到的值=43
找到: 9889
第1组()匹配到的值=98
第2组()匹配到的值=89

image-20210718104008335

2. 正则表达式的语法

基本介绍

如果想要灵活的运用正则表达式,必须了解其中各种元字符的功能,元字符从功能上大致分为

  1. 限定符
  2. 选择匹配符
  3. 分组组合和反向引用符号
  4. 特殊字符
  5. 字符匹配符
  6. 定位符

元字符(Metacharacter)-转义号 \\

\\符号说明:在我们使用正则表达式区检索某些特殊字符的时候,需要用到转义符号,否则检索不到结果,甚至会报错。案例:用$区匹配”abc$(“会怎样?用(去匹配”abc$(“会怎样?

再次提示:在java的正则表达式中,两个\\代表其他语言中的一个\

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.hspedu.regexp; 
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegExp02 {
public static void main(String[] args) {
String content = "abc$(a.bc(123( )";
//匹配( => \\(
//匹配. => \\.
//String regStr = "\\.";
//String regStr = "\\d\\d\\d";
String regStr = "\\d{3}";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);

while (matcher.find()) {
System.out.println("找到 " + matcher.group(0));
}
}
}

找到 123

需要用到转义符号的字符有以下:.*+()$/?[]^{}

元字符-字符匹配符

符号 含义 示例 解释 匹配输入
[] 可接收的字符列表 [efgh] e、f、g、h中的任意1个字符 e
[^] 不可接收的字符列表 [^abc] 除a、b、c之外的任意1个字符,包括数字和特殊符号 4
- 连字符 A-Z 任意单个大写字母 F
. 匹配除\n以外的任何字符 a..b 以a开头,b结尾,中间包括2个任意字符的长度为4的字符串 akjb
\\d 匹配单个数字字符,相当于[0-9] \\d{3}(\\d)? 包含3个或4个数字的字符串 123
\\D 匹配单个非数字字符,相当于[^0-9] \\D(\\d)* 以单个非数字字符开头,后接任意个数字字符串 a
\\w 匹配单个非数字、大小写字母符,相当于[0-9a-zA-Z] \\d{3}\\w{4} 以3个数字字符开头长度为7的数字字符字母串符 234abcd
\\W 匹配单个非数字、大小写字母符,相当于[^0-9a-zA-Z] \\W+\\d{2} 以至少1个非数字字母字符开头,2个数字字符结尾的字符串 #34
\\s 匹配任何空白字符(空格,制表符等) \\W+\\s\\d{2} 以至少1个非数字字母字符开头,中间是空白字符,2个数字字符结尾的字符串 # 34
\\S 匹配任何非空白字符 \\W+\\S\d{2} 以至少1个非数字字母字符开头,中间是非空白字符,2个数字字符结尾的字符串 #234

应用实例

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
32
33
34
35
package 练习;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/*
演示字符匹配符的使用
*/
public class RegExp03 {
public static void main(String[] args) {
String content = "abc11c8ABC";
// String regStr = "[a-z]";//匹配a-z之间任意一个字符
// String regStr = "[A-Z]";//匹配A-Z之间任意一个字符
String regStr = "(?i)abc";//匹配abc字符串[不区分大小写]
//1. 先创建一个Pattern对象 , 模式对象, 可以理解成就是一个正则表达式对象
Pattern pattern = Pattern.compile(regStr);
//2. 创建一个匹配器对象
//理解: 就是 matcher 匹配器按照 pattern(模式/样式), 到 content 文本中去匹配
//找到就返回true, 否则就返回false
Matcher matcher = pattern.matcher(content);
//3. 可以开始循环匹配
while (matcher.find()){
System.out.println("找到 " + matcher.group(0));
}

String cont = "abc12323ABC";
String reg = "abc";
//将模式对象设置为大小写不敏感的
Pattern pattern1 = Pattern.compile(reg,Pattern.CASE_INSENSITIVE);
Matcher matcher1 = pattern1.matcher(cont);
while (matcher1.find()){
System.out.println("方式二找到: " + matcher1.group());
}
}
}

找到 abc
找到 ABC
方式二找到: abc
方式二找到: ABC

元字符-选择匹配符

在匹配某个字符串的时候是选择性的,即:既可以匹配这个又可以匹配那个,这时需要用到选择匹配符

符号 含义 示例 解释
| 匹配”|”之前或者之后的表达式 ab|cd ab|cd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package 练习;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegExpSelect {
public static void main(String[] args) {
String content = "xiongzhuo 熊卓 ( ̄(工) ̄) 🐻";
String regStr = "xiong|熊|\\( ̄\\(工\\) ̄\\)|🐻";
Pattern pat = Pattern.compile(regStr);
Matcher mat = pat.matcher(content);
while (mat.find()){
System.out.println("找到 " + mat.group(0));
}
}
}

找到 xiong
找到 熊
找到 ( ̄(工) ̄)
找到 🐻

*元字符-限定符**

用于指定其前面的字符和组合项连续出现多少次

符号 含义 示例 说明 匹配输入
* 指定字符重复0此或n次(无要求) (abc)* 仅包含任意个abc的字符串 abcabcabc
+ 指定字符重复1次或n次(至少1次) m+(abc)* 以至少1个m开头,后接任意个abc的字符串 mabcabc
? 指定字符重复0次或1次(最多1次) m+abc? 以至少一个m开头,后接ab或abc的字符串 mab
{n} 只能输入n个字符 [abcd]{3} 由abcd中字母组成任意长度为3的字符串 aaa
{n,} 指定至少n个匹配 [abcd]{3,} 由abcd中字母组成的任意长度不小于3的字符串 aabcc
{n,m} 指定至少n个但不多于m个匹配 [abcd]{3,5} 由abcd中字母组成的任意长度不小于3,不大于5的字符串 abccc
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
35
36
37
38
39
40
41
42
43
package com.xiongzhuo.regexp;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* 演示限定符的使用
*/
public class RegExp05 {
public static void main(String[] args) {
String content = "a211111aaaaaahello";

//a{3},1{4},\\d{2}
//String regStr = "a{3}";// 表示匹配 aaa
//String regStr = "1{4}";// 表示匹配 1111
//String regStr = "\\d{2}";// 表示匹配 两位的任意数字字符

//a{3,4},1{4,5},\\d{2,5}

//细节:java匹配默认贪婪匹配,即尽可能匹配多的
//String regStr = "a{3,4}"; //表示匹配 aaa 或者 aaaa
//String regStr = "1{4,5}"; //表示匹配 1111 或者 11111
//String regStr = "\\d{2,5}"; //匹配2位数或者3,4,5


//1+
//String regStr = "1+"; //匹配一个1或者多个1
//String regStr = "\\d+"; //匹配一个数字或者多个数字

//1*
//String regStr = "1*"; //匹配0个1或者多个1

//演示?的使用, 遵守贪婪匹配
String regStr = "a1?"; //匹配 a 或者 a1
Pattern pattern = Pattern.compile(regStr/*, Pattern.CASE_INSENSITIVE*/);
Matcher matcher = pattern.matcher(content);


while (matcher.find()) {
System.out.println("找到 " + matcher.group(0));
}
}

**元字符-定位符 **

定位符,规定要匹配的字符串出现的位置,比如在字符串的开始还是结束的位置

符号 含义 示例 说明 匹配输入
^ 指定起始字符 ^[0-9]+[a-z]* 以至少1个数字开头,后接任意个小写字母的字符串 12dfsa
$ 指定结束字符 ^[0-9]\\-[a-z]+$ 以1个数字开头后接连字符”-“,并以至少1个小写字母结尾的字符串 1-a
\\b 匹配目标字符串的边界 zhuo\\b 这里说的字符串的边界指的是子串间有空格,或者是目标字符串的结束位置 xiongzhuo zhuo zhuo
\\B 匹配目标字符串的非边界 xiong\\B 和\b的含义相反 xiongzhuo zhuo zhuo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package 练习;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegExpLocation {
public static void main(String[] args) {
String content = "1998-xiongzhuo";
String regStr = "^[0-9]+\\-[a-z]+$";
Pattern pat = Pattern.compile(regStr);
Matcher mat = pat.matcher(content);
while(mat.find()){
System.out.println("找到 " + mat.group());
}
}
}

找到 1998-xiongzhuo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package 练习;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegExpLocation {
public static void main(String[] args) {
String content = "1998-xiongzhuoxiongzhuo xiongzhuo xiongzzz zzzxiong";
//String regStr = "^[0-9]+\\-[a-z]+$";
//String regStr = "zhuo\\b";
String regStr = "xiong\\B";
Pattern pat = Pattern.compile(regStr);
Matcher mat = pat.matcher(content);
while(mat.find()){
System.out.println("找到 " + mat.group());
}
}
}

找到 xiong
找到 xiong
找到 xiong
找到 xiong

分组

常用分组构造形式 说明
(pattern) 非命名捕获。捕获匹配的子字符串。编号为零的第一个捕获是由整个正则表达式模式匹配的文本,其他捕获结果则是更具左括号的顺序从1开始自动编号
(?pattern) 命名捕获。将匹配的子字符串捕获到一个组名称或者编号名称中。用于name的字符不能包含任何标点符号,并且不能以数字开头。可以使用单引号代替尖括号,例如(?’name’)
(?:pattern) 匹配pattern但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于用”or”字符(|)组合模式部件的情况很有用。例如,’industr(?:y|ies)’是比‘industry|industries’更经济的表达式
(?=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
package 练习;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegExpGrouping {
public static void main(String[] args) {
String content = "xiongzhuo 1998 0415";
String regStr = "(?<group1>\\d\\d)(?<group2>\\d)(?<group3>\\d)";
Pattern pat = Pattern.compile(regStr);
Matcher mat = pat.matcher(content);
while (mat.find()){
System.out.println("按条件找到 " + mat.group(0));
System.out.println("第一组中按默认编号查找内容 " + mat.group(1));
System.out.println("第一组中按命名进行查找结果 " + mat.group("group1"));
System.out.println("第二组中按默认编号查找内容 " + mat.group(2));
System.out.println("第二组中按命名进行查找结果 " + mat.group("group2"));
System.out.println("第三组中按默认编号查找内容 " + mat.group(3));
System.out.println("第三组中按命名进行查找结果 " + mat.group("group3"));
}
}
}

按条件找到 1998
第一组中按默认编号查找内容 19
第一组中按命名进行查找结果 19
第二组中按默认编号查找内容 9
第二组中按命名进行查找结果 9
第三组中按默认编号查找内容 8
第三组中按命名进行查找结果 8
按条件找到 0415
第一组中按默认编号查找内容 04
第一组中按命名进行查找结果 04
第二组中按默认编号查找内容 1
第二组中按命名进行查找结果 1
第三组中按默认编号查找内容 5
第三组中按命名进行查找结果 5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package 练习;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegExp04 {
public static void main(String[] args) {
String cont = "Windows98 WindowsXP Windows7 Windows8 Windows10 Windows11";
//String regStr = "Windows(?:98|XP|7|8|10|11)";//Windows98 WindowsXP Windows7 Windows8 Windows10 Windows11
//String regStr = "Windows(?=98|XP)";//Windows Windows 只捕获了98和XP的Windows
String regStr = "Windows(?!98|XP)";//Windows Windows Windows Windows 捕获了非98和XP的Windows
Pattern pat = Pattern.compile(regStr);
Matcher mat = pat.matcher(cont);
while (mat.find()){
System.out.println("非捕获匹配 " + mat.group(0));
//未捕获 所以不能分组输出
//System.out.println("非捕获匹配 " + mat.group(1));//No group 1
}
}
}

非贪婪匹配

? 当此字符紧随任何其他限定符(*、+、?、{*n*}、{*n*,}、{*n*,*m*})之后时,匹配模式是”非贪心的”。”非贪心的”模式匹配搜索到的、尽可能短的字符串,而默认的”贪心的”模式匹配搜索到的、尽可能长的字符串。例如,在字符串”oooo”中,”o+?”只匹配单个”o”,而”o+”匹配所有”o”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package 练习;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegExp05 {
public static void main(String[] args) {
String cont = "xionggggggg";
//String regStr = "[g]+";//默认是贪婪匹配 输出ggggggg
//String regStr = "[g]+?";//非贪婪匹配 按最小的匹配 g g g g g g g
String regStr = "[g]{2,3}?";//gg gg gg
Pattern pat = Pattern.compile(regStr);
Matcher mat = pat.matcher(cont);
while(mat.find()){
System.out.println("找到 " + mat.group(0));
}
}
}

3. 应用实例

1.汉字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package 练习;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegExp06 {
public static void main(String[] args) {
String cont = "熊卓的正则学习";
String regStr = "^[\u0391-\uffe5]+$";
Pattern pat = Pattern.compile(regStr);
Matcher mat = pat.matcher(cont);
if(mat.find()){
System.out.println("满足格式");
}else{
System.out.println("不满足格式");
}
}
}

满足格式

2.邮政编码

​ 要求:是1-9开头的一个6位数。比如:123890

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package 练习;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegExp06 {
public static void main(String[] args) {
String cont = "123456 789879787";
String regStr = "^[1-9]\\d{5}$";
Pattern pat = Pattern.compile(regStr);
Matcher mat = pat.matcher(cont);
if(mat.find()){
System.out.println("满足格式");
}else{
System.out.println("不满足格式");
}
}
}

3.QQ号码

​ 要求:是1-9开头的一个(5-10位)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package 练习;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegExp06 {
public static void main(String[] args) {
String cont = "501039430";
String regStr = "^[1-9]\\d{4,9}$";
Pattern pat = Pattern.compile(regStr);
Matcher mat = pat.matcher(cont);
if(mat.find()){
System.out.println("满足格式");
}else{
System.out.println("不满足格式");
}
}
}

4.手机号码

​ 要求:必须以13,14,15,18开头的11位数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package 练习;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegExp06 {
public static void main(String[] args) {
String cont = "15477449565";
String regStr = "^(1(?:3|4|5|8))\\d{9}$";
Pattern pat = Pattern.compile(regStr);
Matcher mat = pat.matcher(cont);
if(mat.find()){
System.out.println("满足格式");
}else{
System.out.println("不满足格式");
}
}
}

5.URL:https://www.bilibili.com/video/BV1fh411y7R8?from=search&seid=1831060912083761326

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
public class RegExp11 {
public static void main(String[] args) {

//String content = "https://www.bilibili.com/video/BV1fh411y7R8?from=search&seid=1831060912083761326";
String content = "http://edu.3dsmax.tech/yg/bilibili/my6652/pc/qg/05-51/index.html#201211-1?track_id=jMc0jn-hm-yHrNfVad37YdhOUh41XYmjlss9zocM26gspY5ArwWuxb4wYWpmh2Q7GzR7doU0wLkViEhUlO1qNtukyAgake2jG1bTd23lR57XzV83E9bAXWkStcAh4j9Dz7a87ThGlqgdCZ2zpQy33a0SVNMfmJLSNnDzJ71TU68Rc-3PKE7VA3kYzjk4RrKU";

/**
* 思路
* 1. 先确定 url 的开始部分 https:// | http://
* 2.然后通过 ([\w-]+\.)+[\w-]+ 匹配 www.bilibili.com
* 3. /video/BV1fh411y7R8?from=sear 匹配(\/[\w-?=&/%.#]*)?
*/
String regStr = "^((http|https)://)?([\\w-]+\\.)+[\\w-]+(\\/[\\w-?=&/%.#]*)?$";//注意:[. ? *]表示匹配就是.本身

Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
if(matcher.find()) {
System.out.println("满足格式");
} else {
System.out.println("不满足格式");
}

//这里如果使用Pattern的matches 整体匹配 比较简洁
System.out.println(Pattern.matches(regStr, content));//

}
}

满足格式
true

4.正则表达式三个常用类

java.util.regx包主要包括以下三个类Pattern类、Matcher类和PatternSyntaxException

  • Pattern类

    pattern对象是一份正则表达式的对象。Pattern类没有公共构造方法。要创建一个Pattern对象,调用其公共静态方法,他返回一个Pattern对象。该方法接收一个正则表达式作为它的第一个参数,比如:Pattern r = Pattern.compile(pattern);

  • Matcher类

    Matcher对象是对输入字符串进行解释和匹配的引擎。与Pattern类一样,Matcher也没有公共构造方法。你需要调用Pattern对象的Matcher方法来获得一个Matcher对象

  • PatternSyntaxException

    PatternSyntaxException是一个非强制异常类,他表示一个正则表达式模式中的语法错误

  • Pattern类的方法matches

    1
    2
    3
    4
    5
    6
    7
    8
    9
    import java.util.regex.Pattern;
    public class Hello{
    public static void main(String[] args){
    String content = "I am xiongzhuo from GUET.huajiang";
    String pattern = ".*GUET.*";
    boolean isMatch = Pattern.matches(pattern,content);
    System.out.println("是否整体匹配成功 " + isMatch);
    }
    }

    是否整体匹配成功 true

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public static boolean matches(String regex, CharSequence input) {
    Pattern p = Pattern.compile(regex);
    Matcher m = p.matcher(input);
    return m.matches();
    }

    public boolean matches() {
    return match(from, ENDANCHOR);
    }
  • Matcher类

    方法一览

方法及说明
public int start() 返回以前匹配的初始索引
public int start(int group) 返回在以前的匹配操作期间,由给定组所捕获的子序列的初始索引
public int end() 返回最后匹配字符之后的偏移量
public int end(int group) 返回在以前的匹配操作期间,由给定组所捕获子序列的最后字符之后的偏移量
public boolean lookingAt() 尝试将从区域开头开始的输入序列与该模式匹配
public boolean find() 尝试查找与该模式匹配的输入序列的下一个子序列
public boolean find(int start) 重置此匹配器,然后尝试查找匹配该模式、从指定索引开始的输入序列的下一个子序列
public boolean matchers() 尝试将整个区域与模式匹配
public Matcher appendReplacement(StringBuffer sb, String replacement)实现非终端添加和替换步骤
public StringBuffer appendTail(StringBuffer sb) 实现终端添加和替换步骤
public String replaceAll(String replacement) 替换模式与给定替换字符串相匹配的输入序列的每个子序列
public String replaceFirst(String replacement) 替换模式与给定替换字符串匹配的输入序列的第一个子序列
public statix String quoteReplacement(String s)返回指定字符串的字面替换字符串。这个方法返回一个字符串,就像传递给Matcher类的appendReplacement方法一个字面字符串一样工作
public Matcher appendReplacement(StringBuffer sb, String replacement)实现非终端添加和替换步骤
public StringBuffer appendTial(StringBuffer sb) 实现终端添加和替换步骤
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
35
36
37
38
39
package com.xiongzhuo.regexp;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* @author 韩顺平
* @version 1.0
* Matcher 类的常用方法
*/
public class MatcherMethod {
public static void main(String[] args) {
String content = "hello xiongzhuotom hello smith hello xiongzhuo xiongzhuo";
String regStr = "hello";

Pattern pattern = Pattern.compile(regStr);
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());

//完成如果content 有 xiongzhuo 替换成 xiongzhuo
regStr = "xiongzhuo";
pattern = Pattern.compile(regStr);
matcher = pattern.matcher(content);
//注意:返回的字符串才是替换后的字符串 原来的 content 不变化
String newContent = matcher.replaceAll("熊卓");
System.out.println("newContent=" + newContent);
System.out.println("content=" + content);

}
}

————————————
0
5
找到: hello
————————————
19
24
找到: hello
————————————
31
36
找到: hello
整体匹配=false
newContent=hello 熊卓tom hello smith hello 熊卓 熊卓
content=hello xiongzhuotom hello smith hello xiongzhuo xiongzhuo

5.分组、捕获、反向引用

  • 介绍

    要解决前面的问题,我们需要了解正则表达式的几个概念:

    1. 分组

      我们可以用圆括号组成一个比较复杂的匹配模式,那么圆括号的部分我们可以看作是一个子表达式/一个分组

    2. 捕获

      把正则表达式中子表达式/分组匹配的内容,保存到内存中以数字编号或显示命名的组里,方便后面引用,从左到右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,并以此类推。组0代表的是整个正则式

    3. 反向引用

      圆括号的内容被捕获后,可以在这个括号后被使用,从而写出一个比较实用的匹配模式,这个我么称为反向引用,这种引用既可以是在正则表达式的内部,也可以是在正则表达式的外部,内部反向引用\\分组号,外部反向引用$分组号

  • 案例

    1. 要匹配两个连续相同的数字

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      package 练习;

      import java.util.regex.Matcher;
      import java.util.regex.Pattern;

      public class RexExpBackReference {
      public static void main(String[] args) {
      String content = "112342455 66 77 4654";
      String regStr = "(\\d)\\1";
      Pattern pat = Pattern.compile(regStr);
      Matcher mat = pat.matcher(content);

      while (mat.find()){
      System.out.println("————————————");
      System.out.println("起始索引 "+mat.start());
      System.out.println("结束索引 "+mat.end());
      System.out.println("找到: " + mat.group(0));

      }
      }
      }

      ————————————
      起始索引 0
      结束索引 2
      找到: 11
      ————————————
      起始索引 7
      结束索引 9
      找到: 55
      ————————————
      起始索引 10
      结束索引 12
      找到: 66
      ————————————
      起始索引 13
      结束索引 15
      找到: 77

    2. 要匹配五个连续相同的数字

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      package 练习;

      import java.util.regex.Matcher;
      import java.util.regex.Pattern;

      public class RexExpBackReference {
      public static void main(String[] args) {
      String content = "111112342455555 66666 77777 4654";
      String regStr = "(\\d)\\1{4}";
      Pattern pat = Pattern.compile(regStr);
      Matcher mat = pat.matcher(content);

      while (mat.find()){
      System.out.println("————————————");
      System.out.println("起始索引 "+mat.start());
      System.out.println("结束索引 "+mat.end());
      System.out.println("找到: " + mat.group(0));

      }
      }
      }

      ————————————
      起始索引 10
      结束索引 15
      找到: 55555
      ————————————
      起始索引 16
      结束索引 21
      找到: 66666
      ————————————
      起始索引 22
      结束索引 27
      找到: 77777

    3. 要匹配个位与千位相同,十位与百位相同的数 5225 1551

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      package 练习;

      import java.util.regex.Matcher;
      import java.util.regex.Pattern;

      public class RexExpBackReference {
      public static void main(String[] args) {
      String content = "12211234245665 6336 7007 4654";
      String regStr = "(\\d)(\\d)\\2\\1";
      Pattern pat = Pattern.compile(regStr);
      Matcher mat = pat.matcher(content);

      while (mat.find()){
      System.out.println("————————————");
      System.out.println("起始索引 "+mat.start());
      System.out.println("结束索引 "+mat.end());
      System.out.println("找到: " + mat.group(0));

      }
      }
      }

      ————————————
      起始索引 0
      结束索引 4
      找到: 1221
      ————————————
      起始索引 10
      结束索引 14
      找到: 5665
      ————————————
      起始索引 15
      结束索引 19
      找到: 6336
      ————————————
      起始索引 20
      结束索引 24
      找到: 7007

    4. 请在字符串中检索商品编号,形式如: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
      package 练习;

      import java.util.regex.Matcher;
      import java.util.regex.Pattern;

      public class RexExpBackReference {
      public static void main(String[] args) {
      String content = "321412321-333999111";
      //以下表达方式等价 每多一个括号就多一个组
      String regStr = "\\d{5}-(\\d)\\1{2}(\\d)\\2{2}(\\d)\\3{2}";
      //String regStr = "(\\d){5}-(\\d)\\2{2}(\\d)\\3{2}(\\d)\\4{2}";
      //String regStr = "((\\d){5})-(\\d)\\3{2}(\\d)\\4{2}(\\d)\\5{2}";
      //String regStr = "(((\\d){5}))-(\\d)\\4{2}(\\d)\\5{2}(\\d)\\6{2}";
      Pattern pat = Pattern.compile(regStr);
      Matcher mat = pat.matcher(content);

      while (mat.find()){
      System.out.println("————————————");
      System.out.println("起始索引 "+mat.start());
      System.out.println("结束索引 "+mat.end());
      System.out.println("找到: " + mat.group(0));

      }

      }
      }

      ————————————
      起始索引 4
      结束索引 19
      找到: 12321-333999111

    5. 结巴去重 我我我…..我要….学学学…学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
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      package com.xiongzhuo.regexp;

      import java.util.regex.Matcher;
      import java.util.regex.Pattern;

      public class RegExp13 {
      public static void main(String[] args) {
      String content = "我....我要....学学学学....编程java!";

      //1. 去掉所有的.

      Pattern pattern = Pattern.compile("\\.");
      Matcher matcher = pattern.matcher(content);
      content = matcher.replaceAll("");

      // System.out.println("content=" + content);

      //2. 去掉重复的字 我我要学学学学编程java!
      // 思路
      //(1) 使用 (.)\\1+
      //(2) 使用 反向引用$1 来替换匹配到的内容
      // 注意:因为正则表达式变化,所以需要重置 matcher
      // pattern = Pattern.compile("(.)\\1+");//分组的捕获内容记录到$1
      // matcher = pattern.matcher(content);
      // while (matcher.find()) {
      // System.out.println("找到=" + matcher.group(0));
      // }
      //
      // //使用 反向引用$1 来替换匹配到的内容
      // content = matcher.replaceAll("$1");
      // System.out.println("content=" + content);

      //3. 使用一条语句 去掉重复的字 我我要学学学学编程java!
      content = Pattern.compile("(.)\\1+").matcher(content).replaceAll("$1");

      System.out.println("content=" + content);

      }
      }

      content=我要学编程java!

6.String类中使用正则表达式

  • 替换功能

    StringReg.java

    String类public String replaceAll(String regx, String replacement)

  • 判断功能

    String类public boolean matchers(String regx){}

    要求验证一个手机号,必须是以138 139开头的

  • 分割功能

    String类public String[] split(String regx)

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
35
36
37
38
package com.xiongzhuo.regexp;

/**
* @author 韩顺平
* @version 1.0
*/
public class StringReg {

public static void main(String[] args) {
String content = "2000年5月,JDK1.3、JDK1.4和J2SE1.3相继发布,几周后其" +
"获得了Apple公司Mac OS X的工业标准的支持。2001年9月24日,J2EE1.3发" +
"布。" +
"2002年2月26日,J2SE1.4发布。自此Java的计算能力有了大幅提升";

//使用正则表达式方式,将 JDK1.3 和 JDK1.4 替换成JDK
content = content.replaceAll("JDK1\\.3|JDK1\\.4", "JDK");
System.out.println(content);

//要求 验证一个 手机号, 要求必须是以138 139 开头的
content = "13888889999";
if (content.matches("1(38|39)\\d{8}")) {
System.out.println("验证成功");
} else {
System.out.println("验证失败");
}


//要求按照 # 或者 - 或者 ~ 或者 数字 来分割
System.out.println("——————————");
content = "hello#abc-jack12smith~北京";
String[] split = content.split("#|-|~|\\d+");
for (String s : split) {
System.out.println(s);
}

}
}

2000年5月,JDK、JDK和J2SE1.3相继发布,几周后其获得了Apple公司Mac OS X的工业标准的支持。2001年9月24日,J2EE1.3发布。2002年2月26日,J2SE1.4发布。自此Java的计算能力有了大幅提升
验证成功
——————————
hello
abc
jack
smith
北京

7.练习

1.验证电子邮件格式是否合法

规定电子邮件规则为

  1. 只能有一个@
  2. @前面是用户名,可以是a-z A-Z 0-9 _-字符
  3. @后面是域名,并且域名只能是英文字母,比如sohu.com 或者 tsinghua.org.cn
  4. 写出对应的正则表达式,验证输入的字符串是否满足规则
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
35
36
37
38
package com.xiongzhuo.regexp;

public class Homework01 {
public static void main(String[] args) {

String content = "hsp@tsinghua.org.cn kkk";
String regStr = "^[\\w-]+@([a-zA-Z]+\\.)+[a-zA-Z]+$";

//1. String 的 matches 是整体匹配
//2. 看看这个matches 底层
/**
* String 的 matches
* public boolean matches(String regex) {
* return Pattern.matches(regex, this);
* }
*
* Pattern
* public static boolean matches(String regex, CharSequence input) {
* Pattern p = Pattern.compile(regex);
* Matcher m = p.matcher(input);
* return m.matches();
* }
*
* Mather类 match
* Attempts to match the entire region against the pattern
* public boolean matches() {
* return match(from, ENDANCHOR);
* }
*/
if (content.matches(regStr)) {
System.out.println("匹配成功");
} else {
System.out.println("匹配失败");
}

}
}

2.要求验证是不是整数或者小数
提示: 这个题要考虑正数和负数
比如: 123 -345 34.89 -87.9 -0.01 0.45 等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.xiongzhuo.regexp;

public class Homework02 {

public static void main(String[] args) {
/**
* 1. 先写出简单的正则表达式
* 2. 在逐步的完善[根据各种情况来完善]
*/
String content = "-0.89"; //
String regStr = "^[-+]?([1-9]\\d*|0)(\\.\\d+)?$";

if(content.matches(regStr)) {
System.out.println("匹配成功 是整数或者小数");
} else {
System.out.println("匹配失败");
}
}
}

3.对一个url进行解析

https://www.souhu.com:8080/abc/index.htm

a)要求得到的协议是什么?http

b)域名是什么? www.sohu.com

c)端口是什么? 8080

d)文件名是什么? index.htm

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
package com.xiongzhuo.regexp;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Homework03 {
public static void main(String[] args) {

String content = "http://www.sohu.com:8080/abc/xxx/yyy/////inde@#$%x.htm";

//因为正则表达式是根据要求来编写的,所以,如果需求需要的话,可以改进.
String regStr = "^([a-zA-Z]+)://([a-zA-Z.]+):(\\d+)[\\w-/]*/([\\w.@#$%]+)$";

Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);

if(matcher.matches()) {//整体匹配, 如果匹配成功,可以通过group(x), 获取对应分组的内容
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.out.println("没有匹配成功");

}

}
}

8.转义字符详细说明

字符 说明
\ 将下一字符标记为特殊字符、文本、反向引用或八进制转义符。例如,”n”匹配字符”n”。”\n”匹配换行符。序列”\\“匹配”\“,”\(“匹配”(“。
^ 匹配输入字符串开始的位置。如果设置了 RegExp 对象的 Multiline 属性,^ 还会与”\n”或”\r”之后的位置匹配。
$ 匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性,$ 还会与”\n”或”\r”之前的位置匹配。
***** 零次或多次匹配前面的字符或子表达式。例如,zo* 匹配”z”和”zoo”。* 等效于 {0,}。
+ 一次或多次匹配前面的字符或子表达式。例如,”zo+”与”zo”和”zoo”匹配,但与”z”不匹配。+ 等效于 {1,}。
? 零次或一次匹配前面的字符或子表达式。例如,”do(es)?”匹配”do”或”does”中的”do”。? 等效于 {0,1}。
{*n*} n\ 是非负整数。正好匹配 *n* 次。例如,”o{2}”与”Bob”中的”o”不匹配,但与”food”中的两个”o”匹配。
{*n*,} n\ 是非负整数。至少匹配 *n* 次。例如,”o{2,}”不匹配”Bob”中的”o”,而匹配”foooood”中的所有 o。”o{1,}”等效于”o+”。”o{0,}”等效于”o*“。
{*n*,*m*} m\ 和 *n* 是非负整数,其中 *n* <= *m*。匹配至少 *n* 次,至多 *m* 次。例如,”o{1,3}”匹配”fooooood”中的头三个 o。’o{0,1}’ 等效于 ‘o?’。注意:您不能将空格插入逗号和数字之间。
? 当此字符紧随任何其他限定符(*、+、?、{*n*}、{*n*,}、{*n*,*m*})之后时,匹配模式是”非贪心的”。”非贪心的”模式匹配搜索到的、尽可能短的字符串,而默认的”贪心的”模式匹配搜索到的、尽可能长的字符串。例如,在字符串”oooo”中,”o+?”只匹配单个”o”,而”o+”匹配所有”o”。
. 匹配除”\r\n”之外的任何单个字符。若要匹配包括”\r\n”在内的任意字符,请使用诸如”[\s\S]”之类的模式。
(*pattern*) 匹配 *pattern* 并捕获该匹配的子表达式。可以使用 $0…$9 属性从结果”匹配”集合中检索捕获的匹配。若要匹配括号字符 ( ),请使用”(“或者”)“。
(?:*pattern*) 匹配 *pattern* 但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于用”or”字符 (|) 组合模式部件的情况很有用。例如,’industr(?:y|ies) 是比 ‘industry|industries’ 更经济的表达式。
(?=*pattern*) 执行正向预测先行搜索的子表达式,该表达式匹配处于匹配 *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”。预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。
x**|*y*** 匹配 *x* 或 *y*。例如,’z|food’ 匹配”z”或”food”。’(z|f)ood’ 匹配”zood”或”food”。
[*xyz*] 字符集。匹配包含的任一字符。例如,”[abc]”匹配”plain”中的”a”。
[^*xyz*] 反向字符集。匹配未包含的任何字符。例如,”[^abc]”匹配”plain”中”p”,”l”,”i”,”n”。
[*a-z*] 字符范围。匹配指定范围内的任何字符。例如,”[a-z]”匹配”a”到”z”范围内的任何小写字母。
[^*a-z*] 反向范围字符。匹配不在指定的范围内的任何字符。例如,”[^a-z]”匹配任何不在”a”到”z”范围内的任何字符。
\b 匹配一个字边界,即字与空格间的位置。例如,”er\b”匹配”never”中的”er”,但不匹配”verb”中的”er”。
\B 非字边界匹配。”er\B”匹配”verb”中的”er”,但不匹配”never”中的”er”。
\c*x* 匹配 *x* 指示的控制字符。例如,\cM 匹配 Control-M 或回车符。*x* 的值必须在 A-Z 或 a-z 之间。如果不是这样,则假定 c 就是”c”字符本身。
\d 数字字符匹配。等效于 [0-9]。
\D 非数字字符匹配。等效于 [^0-9]。
\f 换页符匹配。等效于 \x0c 和 \cL。
\n 换行符匹配。等效于 \x0a 和 \cJ。
\r 匹配一个回车符。等效于 \x0d 和 \cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等。与 [ \f\n\r\t\v] 等效。
\S 匹配任何非空白字符。与 [^ \f\n\r\t\v] 等效。
\t 制表符匹配。与 \x09 和 \cI 等效。
\v 垂直制表符匹配。与 \x0b 和 \cK 等效。
\w 匹配任何字类字符,包括下划线。与”[A-Za-z0-9_]”等效。
\W 与任何非单词字符匹配。与”[^A-Za-z0-9_]”等效。
\x*n* 匹配 *n*,此处的 *n* 是一个十六进制转义码。十六进制转义码必须正好是两位数长。例如,”\x41”匹配”A”。”\x041”与”\x04”&”1”等效。允许在正则表达式中使用 ASCII 代码。
*num* 匹配 *num*,此处的 *num* 是一个正整数。到捕获匹配的反向引用。例如,”(.)\1”匹配两个连续的相同字符。
*n* 标识一个八进制转义码或反向引用。如果 *n* 前面至少有 *n* 个捕获子表达式,那么 *n* 是反向引用。否则,如果 *n* 是八进制数 (0-7),那么 *n* 是八进制转义码。
*nm* 标识一个八进制转义码或反向引用。如果 *nm* 前面至少有 *nm* 个捕获子表达式,那么 *nm* 是反向引用。如果 *nm* 前面至少有 *n* 个捕获,则 *n* 是反向引用,后面跟有字符 *m*。如果两种前面的情况都不存在,则 *nm* 匹配八进制值 *nm*,其中 *n* 和 *m* 是八进制数字 (0-7)。
\nml 当 *n* 是八进制数 (0-3),*m* 和 *l* 是八进制数 (0-7) 时,匹配八进制转义码 *nml*。
\u*n* 匹配 *n*,其中 *n* 是以四位十六进制数表示的 Unicode 字符。例如,\u00A9 匹配版权符号 (©)。

9.正则表达式参考

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
一、校验数字的表达式

1 数字:^[0-9]*$
2 n位的数字:^\d{n}$
3 至少n位的数字:^\d{n,}$
4 m-n位的数字:^\d{m,n}$
5 零和非零开头的数字:^(0|[1-9][0-9]*)$
6 非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?$
71-2位小数的正数或负数:^(\-)?\d+(\.\d{1,2})?$
8 正数、负数、和小数:^(\-|\+)?\d+(\.\d+)?$
9 有两位小数的正实数:^[0-9]+(.[0-9]{2})?$
101~3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$
11 非零的正整数:^[1-9]\d*$ 或 ^([1-9][0-9]*){1,3}$ 或 ^\+?[1-9][0-9]*$
12 非零的负整数:^\-[1-9][]0-9"*$ 或 ^-[1-9]\d*$
13 非负整数:^\d+$ 或 ^[1-9]\d*|0$
14 非正整数:^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$
15 非负浮点数:^\d+(\.\d+)?$ 或 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$
16 非正浮点数:^((-\d+(\.\d+)?)|(0+(\.0+)?))$ 或 ^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$
17 正浮点数:^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ 或 ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$
18 负浮点数:^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ 或 ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$
19 浮点数:^(-?\d+)(\.\d+)?$ 或 ^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$




二、校验字符的表达式

1 汉字:^[\u4e00-\u9fa5]{0,}$
2 英文和数字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$
3 长度为3-20的所有字符:^.{3,20}$
4 由26个英文字母组成的字符串:^[A-Za-z]+$
5 由26个大写英文字母组成的字符串:^[A-Z]+$
6 由26个小写英文字母组成的字符串:^[a-z]+$
7 由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
8 由数字、26个英文字母或者下划线组成的字符串:^\w+$ 或 ^\w{3,20}$
9 中文、英文、数字包括下划线:^[\u4E00-\u9FA5A-Za-z0-9_]+$
10 中文、英文、数字但不包括下划线等符号:^[\u4E00-\u9FA5A-Za-z0-9]+$ 或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$
11 可以输入含有^%&',;=?$\"等字符:[^%&',;=?$\x22]+
12 禁止输入含有~的字符:[^~\x22]+




三、特殊需求表达式




1 Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
2 域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
3 InternetURL:[a-zA-z]+://[^\s]* 或 ^https://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$
4 手机号码:^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$
5 电话号码("XXX-XXXXXXX"、"XXXX-XXXXXXXX"、"XXX-XXXXXXX"、"XXX-XXXXXXXX"、"XXXXXXX"和"XXXXXXXX):^(\(\d{3,4}-)|\d{3.4}-)?\d{7,8}$
6 国内电话号码(0511-4405222021-87888822):\d{3}-\d{8}|\d{4}-\d{7}
7 身份证号:
1518位身份证:^\d{15}|\d{18}$
15位身份证:^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$
18位身份证:^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{4}$
8 短身份证号码(数字、字母x结尾):^([0-9]){7,18}(x|X)?$ 或 ^\d{8,18}|[0-9x]{8,18}|[0-9X]{8,18}?$
9 帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
10 密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$
11 强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
12 日期格式:^\d{4}-\d{1,2}-\d{1,2}
13 一年的12个月(01~09和112):^(0?[1-9]|1[0-2])$
14 一个月的31天(01~09和131):^((0?[1-9])|((1|2)[0-9])|30|31)$
15 钱的输入格式:
16 1.有四种钱的表示形式我们可以接受:"10000.00""10,000.00", 和没有 "分""10000""10,000":^[1-9][0-9]*$
17 2.这表示任意一个不以0开头的数字,但是,这也意味着一个字符"0"不通过,所以我们采用下面的形式:^(0|[1-9][0-9]*)$
18 3.一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号:^(0|-?[1-9][0-9]*)$
19 4.这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧.下面我们要加的是说明可能的小数部分:^[0-9]+(.[0-9]+)?$
20 5.必须说明的是,小数点后面至少应该有1位数,所以"10."是不通过的,但是 "10""10.2" 是通过的:^[0-9]+(.[0-9]{2})?$
21 6.这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:^[0-9]+(.[0-9]{1,2})?$
22 7.这样就允许用户只写一位小数.下面我们该考虑数字中的逗号了,我们可以这样:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$
23 8.13个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$
24 备注:这就是最终结果了,别忘了"+"可以用"*"替代如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里
25 xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$
26 中文字符的正则表达式:[\u4e00-\u9fa5]
27 双字节字符:[^\x00-\xff] (包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))
28 空白行的正则表达式:\n\s*\r (可以用来删除空白行)
29 HTML标记的正则表达式:<(\S*?)[^>]*>.*?|<.*? /> (网上流传的版本太糟糕,上面这个也仅仅能部分,对于复杂的嵌套标记依旧无能为力)
30 首尾空白字符的正则表达式:^\s*|\s*$或(^\s*)|(\s*$) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)
31 腾讯QQ号:[1-9][0-9]{4,} (腾讯QQ号从10000开始)
32 中国邮政编码:[1-9]\d{5}(?!\d) (中国邮政编码为6位数字)
33 IP地址:\d+\.\d+\.\d+\.\d+ (提取IP地址时有用)