[Java learning from 0 to 1] 09 regular expressions

09 regular expressions

1. Overview of regular expressions

When writing programs or web pages that process strings, there is often a need to find strings that match some complex rules. Regular expressions are tools used to describe these rules. In other words, regular expressions are codes that record text rules.

Regular expressions, also known as regular expressions and regular expressions (English: Regular Expression, often abbreviated as regex, regexp or RE in code), are a concept in computer science. Regular expressions use a single string to describe and match a series of strings that match a certain syntax rule. In many text editors, regular expressions are often used to retrieve and replace text that matches a certain pattern.

Many programming languages ​​support string manipulation using regular expressions. For example, Perl has a powerful regular expression engine built into it. The concept of regular expressions was originally popularized by tool software in Unix (such as sed and grep). Regular expressions are often abbreviated as "regex", the singular includes regexp, regex, and the plural includes regexps, regexes, and regexen.

A regular expression is a logical formula for string operations. It uses some predefined specific characters and combinations of these specific characters to form a "regular string". This "regular string" is used to express a pair of characters. A filtering logic for strings

1.1 Purpose of regular expressions

  • Whether the given string matches the filtering logic of the regular expression (called "matching")
  • We can use regular expressions to get the specific part we want from the string

1.2 Features of regular expressions

  • Flexibility, logic and functionality are very strong;
  • Complex control of strings can be achieved quickly and in an extremely simple way.
  • For those who are new to it, it is relatively obscure.

Since the main application object of regular expressions is text, they are used in various text editors. From the famous editor EditPlus to large editors such as Microsoft Word and Visual Studio, regular expressions can be used to process them. text content

2. Basic knowledge of regular expressions

2.1 Metacharacters

Regular expressions rely mostly on metacharacters.

Metacharacters do not represent their literal meaning; they have special meanings. Some metacharacters have special meanings when written within square brackets. The following is an introduction to some metacharacters:

metacharacter describe
. A period matches any single character except newline
[ ] Character type. Matches any character within square brackets
[^ ] Negative character type. Matches any character except square brackets
* Match >=0 repeated characters before the * sign
+ Match >= 1 repeated characters before the + sign
? Characters before the mark? are optional
{n,m} Match num characters before the square brackets (n <= num <= m)
(xyz) character set, matches strings exactly equal to xyz
| OR operator, matches characters before or after the symbol
\ Escape characters, used to match some reserved characters `[ ] ( ) { } . * + ? ^ $ \
^ Start matching from the start line
$ Match from the end

2.2 Common symbols

2.2.1 Characters

symbol illustrate
X CharacterX
\\ backslash
\t Tab('\u0009')
\n Enter
\r newline
\f Form feed character ('\u000C')
\a Alarm (bell) character ('\u0007')

2.2.2 Character class

symbol illustrate
[abc] a, b or c
[^abc] any character except a, b or c
[a-zA-Z] a to z, or A to Z
[0-9] Characters from 0 to 9
[a-d[m-p]] a to d or m to p: [a-dm-p] (union)
[a-z&&[def]] d, e or f (intersection)
[az&&[^bc] a to z, except b and c: [ad-z] (minus)
[az&&[^mp] a to z, not m to p: [a-lq-z] (minus)
\u4E00-\u9FA5 Chinese characters

2.2.3 Predefined characters

symbol illustrate
. any character
\d Number: [0-9]
\D Not a number: [^0-9]
\s Whitespace characters: [ \t\n\x0B\f\r]
\S Non-blank characters: [^\s]
\w Word characters: [a-zA-Z_0-9]
\W Non-word characters: [^\w]

2.3 Bracket expressions

Range matching, a special way of matching a single character.

  • That is, [ ] expression, used to match a single character, but the range of this character is determined by the expression in square brackets
  • Enumeration: [abc], indicating matching any one of a, b, c
  • Range: [a-f], meaning to match any character between af, including the boundary, where the right boundary must ≥ the left boundary, otherwise the engine will compile an error
  • 并:[a-cm-p],就表示a-c的范围和m-p的范围求并,其实前面的abc之类的枚举也是一种并运算
  • 交:[a-z&&b-d],就表示a-z的范围和b-d的范围求交,结果等于[b-d]
  • 补:[^abc]表示非a、b、c的任意一个字符,[^a-f]表示非a-f的任一字符;^也是一个脱字符,必须是中括号表达式的第一个字符,否则不起任何作用。补的是^后面紧跟的整个表达式。
  • 嵌套:[a-m&&[def]]a-m[def]都表示范围,因此可以做运算,结果等于[d-f]
  • 有了上面这些基本运算,就可以构造一些很复杂的运算了:[a-z&&[^bc]] == [ad-z],但是注意不要用^构造复杂表达式,以下一些表达式将不起作用!
    • ^后面紧跟一个[ ]嵌套:^[a-d],非法!不起任何作用
    • ^后面是一个运算(交并补):^a-cf-h^a-z&&c-h^^a-c,都是非法的!!不起任何作用!!
    • ^后面只能跟单纯的枚举和范围运算!!例如[^azh][^a-h]等;

2.4 边界匹配器

符号 说明
^ 行开头
$ 行结尾
\b 单词边界
\B 非单词边界
\A 输入的开头
\G 上一个匹配的结尾
\Z 输入的结尾,仅用于最后的结束符(如果有的话)
\z 输入的结尾

2.4.1 贪婪与懒惰数量词

  • 贪婪数量词
符号 说明
X? 0次或1次
X* 0次以上
X+ 1次以上
X{n} 恰好n次
X{n,} 至少n次
X{n,m} n-m次

当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符。以这个表达式为例:a.*b,它将会匹配最长的以a开始,以b结束的字符串。如果用它来搜索aabab的话,它会匹配整个字符串aabab。这被称为贪婪匹配。

有时,我们更需要懒惰匹配,也就是匹配尽可能少的字符。在贪婪数量词后面加上?就是懒惰匹配。这样.*?就意味着匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复。现在看看懒惰版的例子吧:

a.*?b匹配最短的,以a开始,以b结束的字符串。如果把它应用于aabab的话,它会匹配aab(第一到第三个字符)和ab(第四到第五个字符)。

为什么第一个匹配是aab(第一到第三个字符)而不是ab(第二到第三个字符)?简单地说,因为正则表达式有另一条规则,比懒惰/贪婪规则的优先级更高:最先开始的匹配拥有最高的优先权——The match that begins earliest wins

  • 懒惰限定符
代码/语法 说明
*? 重复任意次,但尽可能少重复
+? 重复1次或更多次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复

2.4.2 分组和捕获

分组可以分为两种形式,捕获组和非捕获组。

1、捕获组

捕获组可以通过从左到右计算其开括号来编号。例如,在表达式 ((A)(B©))中,存在四个这样的组:

  • 分组0:((A)(B(C)))
  • 分组1:(A)
  • 分组2:(B(C))
  • 分组3:(C)

正则表达式中每个"()"内的部分算作一个捕获组,每个捕获组都有一个编号,从1,2…,编号0代表整个匹配到的内容,组零始终代表整个表达式。

之所以这样命名捕获组是因为在匹配中,保存了与这些组匹配的输入序列的每个子序列。捕获的子序列稍后可以通过 Back 引用(反向引用) 在表达式中使用,也可以在匹配操作完成后从匹配器检索。

Back引用(\n)是说在后面的表达式中我们可以使用组的编号来引用前面的表达式所捕获到的文本序列。注意:反向引用,引用的是前面捕获组中的文本而不是正则,也就是说反向引用处匹配的文本应和前面捕获组中的文本相同,这一点很重要。

例如 ([" ']).*\1 其中使用了分组,\1就是对引号这个分组的引用,它匹配包含在两个引号或者两个单引号中的所有字符串,如,“abc” 或 "’ " 或’ " ’ ,但是请注意,它并不会对"a’或者 'a"匹配。原因上面已经说明,Back引用只是引用文本而不是表达式。

捕获组的作用就是为了可以在正则表达式内部或者外部(Java方法)引用它。在另一个字符串引用捕获组的内容的方法(“$”),在替换中常用$匹配组的内容。$n用来匹配第n个()里的内容。

利用Matcher中的group(int group)获取捕获组内容。

2、捕获组命名

如果捕获组的数量非常多,那都用数字进行编号并引用将会非常混乱,并且难以记忆每个捕获组的内容及意义,因此对捕获组命名显得尤为重要;Java 7开始提供了对捕获组命名的语法,并且可以通过捕获组的名称对捕获组反向引用(内外都行)。

命名捕获组的语法格式:(?<自定义名>expr),例如:(?<year>\d{4})-(?<date>\d{2}-(?<day>\d{2})),有三个命名捕获组year、date和day,从左到右编号分别为1、2、3(编号同样是有效的)

命名捕获组的反向引用:

  • 正则表达式内引用:\k<捕获组名称>,例如:(?<year>\d{4})-\k<year>可以匹配1999-1999
  • 外部引用:Matcher对象的start、end、group的String name参数指定要查询的捕获组的名称。

普通捕获组和命名捕获组的混合编号:

  • 普通捕获组是相对命名捕获组的,即没有显式命名的捕获组;
  • 当所有捕获组都是命名捕获组时那么编号规则和原来相同,即按照左括号(的出现顺序来编号;
  • 当普通捕获组和命名捕获组同时出现时,编号规则为:先不忽略命名捕获组,只对普通捕获组按照左括号顺序编号,然后再对命名捕获组从左往右累计编号,例如:先忽略命名命名捕获组<date>,先对普通捕获组编号\d{4}是1,\d\d是2,然后再接着累加地对命名捕获组编号,因此<date>是3;

3、非捕获组

非捕获组,只需要将捕获组中"()“变为”(?:)"即可。

以 (?) 开头的组是纯的非捕获组,它不捕获文本 ,也不针对组合计进行计数。就是说,如果小括号中以?号开头,那么这个分组就不会捕获文本,当然也不会有组的编号,因此也不存在Back引用。

我们通过捕获组就能够得到我们想要匹配的内容了,那为什么还要有非捕获组呢?原因是捕获组捕获的内容是被存储在内存中,可供以后使用,比如反向引用就是引用的内存中存储的捕获组中捕获的内容。而非捕获组则不会捕获文本,也不会将它匹配到的内容单独分组来放到内存中。所以,使用非捕获组较使用捕获组更节省内存。在实际情况中我们要酌情选用。

2.5 前后关联约束(前后预查)

前置约束和后置约束都属于非捕获簇(用于匹配不在匹配列表中的格式)。 前置约束用于判断所匹配的格式是否在另一个确定的格式之后。

例如, 我们想要获得所有跟在 $ 符号后的数字, 我们可以使用正向向后约束 (?<=\$)[0-9\.]*。这个表达式匹配 $ 开头, 之后跟着 0,1,2,3,4,5,6,7,8,9,. 这些字符可以出现大于等于 0 次。

前后关联约束如下:

符号 描述
?= 前置约束-存在
?! 前置约束-排除
?<= 后置约束-存在
?<! 后置约束-排除

?=exp前置约束(存在)

?=exp 前置约束(存在), 表示第一部分表达式必须跟在 ?=exp 定义的表达式之后.

返回结果只瞒住第一部分表达式. 定义一个前置约束(存在)要使用 (). 在括号内部使用一个问号和等号: (?=exp).

前置约束的内容写在括号中的等号后面. 例如, 表达式 [T|t]he(?=\sfat) 匹配 Thethe, 在括号中我们又定义了前置约束(存在) (?=\sfat) ,即 Thethe 后面紧跟着 (空格)fat.

"[T|t]he(?=\sfat)" => The fat cat sat on the mat.

?!exp前置约束-排除

前置约束-排除 ?! 用于筛选所有匹配结果, 筛选条件为 其后不跟随着定义的格式 前置约束-排除 定义和 前置约束(存在) 一样, 区别就是 = 替换成 ! 也就是 (?!exp).

表达式 [T|t]he(?!\sfat) 匹配 Thethe, 且其后不跟着 (空格)fat.

"[T|t]he(?!\sfat)" => The fat cat sat on the mat.

?<=exp后置约束-存在

后置约束-存在 记作(?<=exp)用于筛选所有匹配结果, 筛选条件为 其前跟随着定义的格式. 例如, 表达式 (?<=[T|t]he\s)(fat|mat) 匹配 fatmat, 且其前跟着 Thethe.

"(?<=[T|t]he\s)(fat|mat)" => The fat cat sat on the mat.

?<!exp后置约束-排除

后置约束-排除 记作 (?<!exp)用于筛选所有匹配结果, 筛选条件为 其前不跟着定义的格式. 例如, 表达式 (?<!(T|t)he\s)(cat)匹配 cat, 且其前不跟着 Thethe.

"(?<![T|t]he\s)(cat)" => The cat sat on cat.

2.6 标志

标志也叫修饰语, 因为它可以用来修改表达式的搜索结果. 这些标志可以任意的组合使用, 它也是整个正则表达式的一部分.

标志 描述
i 忽略大小写.
g 全局搜索.
m 多行的: 锚点元字符 ^ $ 工作范围在每行的起始.

忽略大小写 (Case Insensitive)

修饰语 i 用于忽略大小写. 例如, 表达式 /The/gi 表示在全局搜索 The, 在后面的 i 将其条件修改为忽略大小写, 则变成搜索 theThe, g 表示全局搜索.

"The" => The fat cat sat on the mat.
"/The/gi" => The fat cat sat on the mat.

全局搜索 (Global search)

修饰符 g 常用语执行一个全局搜索匹配, 即(不仅仅返回第一个匹配的, 而是返回全部). 例如, 表达式 /.(at)/g 表示搜索 任意字符(除了换行) + at, 并返回全部结果.

"/.(at)/" => The fat cat sat on the mat.
"/.(at)/g" => The fat cat sat on the mat.

多行修饰符 (Multiline)

多行修饰符 m 常用语执行一个多行匹配.

像之前介绍的 (^,$) 用于检查格式是否是在待检测字符串的开头或结尾. 但我们如果想要它在每行的开头和结尾生效, 我们需要用到多行修饰符 m.

例如, 表达式 /at(.)?$/gm 表示在待检测字符串每行的末尾搜索 at后跟一个或多个 . 的字符串, 并返回全部结果.

"/.at(.)?$/" => The fat
                cat sat
                on the mat.
                
"/.at(.)?$/gm" => The fat
                  cat sat
                  on the mat.

3. 正则表达式的应用

String 类提供的几个特殊方法

方法声明 功能描述
matches() 判断该字符串是否匹配指定的正则表达式
replaceAll() 将该字符串所有匹配正则表达式的子串替换成指定的字符串
replaceFirst() 将该字符串中第一个匹配正则表达式的子串替换成指定的字符串
split(String regex) 以regex为分隔符,将该字符串分割成多个子串

3.1 匹配功能

public  boolean matches(String regex) // 编译给定正则表达式并尝试将给定输入与其匹配。

校验邮箱

package cn.itcast_02;
import java.util.Scanner;
/*
 * 校验邮箱
 * 
 * 分析:
 * 		A:键盘录入邮箱
 * 		B:定义邮箱的规则
 * 			[email protected]
 * 			[email protected]
 * 			[email protected]
 * 			[email protected]
 * 			[email protected]
 * 		C:调用功能,判断即可
 * 		D:输出结果
 */
public class RegexTest {
    
    
	public static void main(String[] args) {
    
    
		//键盘录入邮箱
		Scanner sc = new Scanner(System.in);
		System.out.println("请输入邮箱:");
		String email = sc.nextLine();
		
		//定义邮箱的规则
		//String regex = "[a-zA-Z_0-9]+@[a-zA-Z_0-9]{2,6}(\\.[a-zA-Z_0-9]{2,3})+";
		String regex = "\\w+@\\w{2,6}(\\.\\w{2,3})+";
		
		//调用功能,判断即可
		boolean flag = email.matches(regex);
		
		//输出结果
		System.out.println("flag:"+flag);
	}
}

3.2 分割功能

public  String[] split(String regex) // 根据指定的正则表达式分割字符串

代码示例:我有如下一个字符串:”91 27 46 38 50”,请写代码实现最终输出结果是:”27 38 46 50 91”

package cn.itcast_03;
import java.util.Arrays;
/*
 * 我有如下一个字符串:"91 27 46 38 50"
 * 请写代码实现最终输出结果是:"27 38 46 50 91"
 * 
 * 分析:
 * 		A:定义一个字符串
 * 		B:把字符串进行分割,得到一个字符串数组
 * 		C:把字符串数组变换成int数组
 * 		D:对int数组排序
 * 		E:把排序后的int数组在组装成一个字符串
 * 		F:输出字符串
 */
public class RegexTest {
    
    
	public static void main(String[] args) {
    
    
		// 定义一个字符串
		String s = "91 27 46 38 50";

		// 把字符串进行分割,得到一个字符串数组
		String[] strArray = s.split(" ");

		// 把字符串数组变换成int数组
		int[] arr = new int[strArray.length];

		for (int x = 0; x < arr.length; x++) {
    
    
			arr[x] = Integer.parseInt(strArray[x]);
		}

		// 对int数组排序
		Arrays.sort(arr);

		// 把排序后的int数组在组装成一个字符串
		StringBuilder sb = new StringBuilder();
		for (int x = 0; x < arr.length; x++) {
    
    
			sb.append(arr[x]).append(" ");
		}
		//转化为字符串
		String result = sb.toString().trim();
		
		//输出字符串
		System.out.println("result:"+result);
	}
}

3.3 替换功能

public  String replaceAll(String regex,String replacement)

使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。

  • 论坛中不能出现数字字符,用*替换
package cn.itcast_04;
/*
 * 替换功能
 *  	String类的public String replaceAll(String regex,String replacement)
 *  	使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。 
 */
public class RegexDemo {
    
    
	public static void main(String[] args) {
    
    
		// 定义一个字符串
		String s = "helloqq12345worldkh622112345678java";

		// 我要去除所有的数字,用*给替换掉
		// String regex = "\\d+";
		// String regex = "\\d";
		//String ss = "*";
		
		
		// 直接把数字干掉
		String regex = "\\d+";
		String ss = "";

		String result = s.replaceAll(regex, ss);
		System.out.println(result);
	}
}

3.4 获取功能

Pattern和Matcher类的使用

package cn.itcast_05;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/*
 * 获取功能
 *		Pattern和Matcher类的使用
 *		
 *		模式和匹配器的基本使用顺序
 */
public class RegexDemo {
    
    
	public static void main(String[] args) {
    
    
		// 模式和匹配器的典型调用顺序
		// 把正则表达式编译成模式对象
		Pattern p = Pattern.compile("a*b");
		// 通过模式对象得到匹配器对象,这个时候需要的是被匹配的字符串
		Matcher m = p.matcher("aaaaab");
		// 调用匹配器对象的功能
		boolean b = m.matches();
		System.out.println(b);
		
		//这个是判断功能,但是如果做判断,这样做就有点麻烦了,我们直接用字符串的方法做
		String s = "aaaaab";
		String regex = "a*b";
		boolean bb = s.matches(regex);
		System.out.println(bb);
	}
}

3.5 Pattern 匹配模式

Pattern类为正则表达式的编译表示形式。指定为字符串的表达式必须首先被编译为此类的实例。然后,可将得到的模式用于创建Matcher对象,依照正则表达式,该对象可与任意字符序列匹配。执行匹配所涉及的所有状态都驻留在匹配器中,所以多个匹配器可以共享同一个模式。

方法声明 功能描述
compile() 把正则表达式编译成匹配模式
matcher() 根据匹配模式去匹配指定的字符串,得到匹配器

3.6 Matcher 匹配器

方法声明 功能描述
matches() 匹配字符串
find() 查找有没有满足条件的子串
group() 获取满足条件的子串
reset() 将Matcher的状态重新设置为最初的状态
reset(CharSequence input) 重新设置Matcher的状态,并且将候选字符序列设置为input后进行Matcher, 这个方法和重新创建一个Matcher一样,只是这样可以重用以前的对象。
start() 返回Matcher所匹配的字符串在整个字符串的的开始下标
start(int group) 指定你感兴趣的sub group,然后返回sup group(子分组)匹配的开始位置。
end() 返回在以前的匹配操作期间,由给定组所捕获子序列的最后字符之后的偏移量。
  • 注意事项

Pattern类为正则表达式的编译表示形式。指定为字符串的正则表达式必须首先被编译为此类的实例。然后,可将得到的模式用于创建Matcher对象,依照正则表达式,该对象可以与任意字符序列匹配。执行匹配所涉及的所有状态都驻留在匹配器中,所以多个匹配器可以共享同一模式

Grouping: To put it simply, grouping is actually to be able to specify how many times the same rule can be used. The grouping in a regular expression is the entire large regular expression and the content enclosed with ().

In this regular expression "\w(\d\d)(\w+)"

  • Group 0: is "\w(\d\d)(\w+)"
  • Group 1: Yes (\d\d)
  • Group 2: Yes (\w+)

If we change it slightly and change the original regular expression to "(\w)(\d\d)(\w+)", our grouping becomes

  • Group 0: is "\w(\d\d)(\w+)"
  • Group 1: is "(\w)"
  • Group 2: is "(\d\d)"
  • Group 3: is "(\w+)"

Let's look at a string A22happy that matches the regular expression "\w(\d\d)(\w+)"

  • group(0) is the part of the string that matches the entire expression A22happy
  • group(1) is the matched part of group 1 (\d\d): 22
  • group(2) is the happy part matched by the second group (\w+)
public static void main(String[] args) {
    
    
	String Regex="\\w(\\d\\d)(\\w+)";
	String TestStr="A22happy";
	Pattern p=Pattern.compile(Regex);
	Matcher matcher=p.matcher(TestStr);
	if (matcher.find()) {
    
    
	    int gc=matcher.groupCount();
	    for (int i = 0; i <= gc; i++) {
    
    
	        System.out.println("group "+i+" :"+matcher.group(i));
	    }
	}
}
  • Use of the start() method
public static void testStart(){
    
    
    //创建一个 Matcher ,使用 Matcher.start()方法
    String candidateString = "My name is Bond. James Bond.";
    String matchHelper[] ={
    
    "          ^","                      ^"};
    Pattern p = Pattern.compile("Bond");
    Matcher matcher = p.matcher(candidateString);
    //找到第一个 'Bond'的开始下标
    matcher.find();
    int startIndex = matcher.start();
    System.out.println(candidateString);
    System.out.println(matchHelper[0] + startIndex);
    //找到第二个'Bond'的开始下标
    matcher.find();
    int nextIndex = matcher.start();
    System.out.println(candidateString);
    System.out.println(matchHelper[1] + nextIndex);        
}

operation result:

/**
  * 测试matcher.group方法
  */
public static void testGroup() {
    
    
    // 创建一个 Pattern
    Pattern p = Pattern.compile("Bond");
    // 创建一个 Matcher ,以便使用 Matcher.group() 方法
    String candidateString = "My name is Bond. James Bond.";
    Matcher matcher = p.matcher(candidateString);
    // 提取 group
    matcher.find();
    System.out.println(String.format("group匹配的字符串 : %s",matcher.group()));
    System.out.println(String.format("匹配的开始位置 : %d", matcher.start()));
    System.out.println(String.format("匹配的结束位置 : %d", matcher.end()));

    System.out
            .println("---再次使用matcher.find()方法,看看matcher中group、start、end方法的效果");
    matcher.find();
    System.out.println(String.format("group匹配的字符串 : %s",matcher.group()));;
    System.out.println(String.format("匹配的开始位置 : %d", matcher.start()));
    System.out.println(String.format("匹配的结束位置 : %d", matcher.end()));
    System.out.println(String.format("candidateString字符串的长度 : %d", candidateString.length()));
}

operation result:

  • Get a word consisting of three characters
package cn.itcast_05;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/*
 * 获取功能:
 * 获取下面这个字符串中由三个字符组成的单词
 * da jia ting wo shuo,jin tian yao xia yu,bu shang wan zi xi,gao xing bu?
 */
public class RegexDemo2 {
    
    
	public static void main(String[] args) {
    
    
		// 定义字符串
		String s = "da jia ting wo shuo,jin tian yao xia yu,bu shang wan zi xi,gao xing bu?";
		// 规则
		String regex = "\\b\\w{3}\\b";

		// 把规则编译成模式对象
		Pattern p = Pattern.compile(regex);
		// 通过模式对象得到匹配器对象
		Matcher m = p.matcher(s);
		// 调用匹配器对象的功能
		// 通过find方法就是查找有没有满足条件的子串
		// public boolean find()
		// boolean flag = m.find();
		// System.out.println(flag);
		// // 如何得到值呢?
		// // public String group()
		// String ss = m.group();
		// System.out.println(ss);
		//
		// // 再来一次
		// flag = m.find();
		// System.out.println(flag);
		// ss = m.group();
		// System.out.println(ss);

		while (m.find()) {
    
    
			System.out.println(m.group());
		}

		// 注意:一定要先find(),然后才能group()
		// IllegalStateException: No match found
		// String ss = m.group();
		// System.out.println(ss);
	}
}
  • Determine the ID card: it is either 15 digits or 18 digits, the last digit can be a letter, and write a program to come up with the year, month and day.
public static void main(String[] args) {
    
    
    testID_Card();
}

public static void testID_Card() {
    
    
    // 测试是否为合法的身份证号码
    String[] strs = {
    
     "130681198712092019", "13068119871209201x",
            "13068119871209201", "123456789012345", "12345678901234x",
            "1234567890123" };
    // 准备正则表达式(身份证有15位和18位两种,身份证的最后一位可能是字母)
    String regex = "(\\d{14}\\w)|\\d{17}\\w";
    // 准备开始匹配,判断所有的输入是否是正确的
    Pattern regular = Pattern.compile(regex); // 创建匹配的规则Patter

    StringBuilder sb = new StringBuilder();
    // 遍历所有要匹配的字符串
    for (int i = 0; i < strs.length; i++) {
    
    

        Matcher matcher = regular.matcher(strs[i]);// 创建一个Matcher
        sb.append("身份证:  ");
        sb.append(strs[i]);
        sb.append("   匹配:");
        sb.append(matcher.matches());
        System.out.println(sb.toString());
        sb.delete(0, sb.length());// 清空StringBuilder的方法
    }

    GetBirthDay(strs);

}

private static void GetBirthDay(String[] strs) {
    
    
    System.out.println("准备开始获取出生日期");
    // 准备验证规则
    Pattern BirthDayRegular = Pattern.compile("(\\d{6})(\\d{8})(.*)");
    // .*连在一起就意味着任意数量的不包含换行的字符
    Pattern YearMonthDayRegular = Pattern.compile("(\\d{4})(\\d{2})(\\d{2})");
    for (int i = 0; i < strs.length; i++) {
    
    
        Matcher matcher = BirthDayRegular.matcher(strs[i]);

        if (matcher.matches()) {
    
    
            Matcher matcher2 = YearMonthDayRegular.matcher(matcher.group(2));
            if (matcher2.matches()) {
    
    
                System.out.println(strs[i]+"    中的出生年月分解为: "+"年" + matcher2.group(1) + "   月:" + matcher2.group(2) + "  日:" + matcher2.group(3));

            }
        }
    }
}

operation result:

4. Regular expression tools

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

/**
 * 正则工具类 提供验证邮箱、手机号、电话号码、身份证号码、数字等方法
 */
public final class RegexUtils {
    
    

	/**
	 * 验证Email
	 * 
	 * @param email
	 *            email地址,格式:[email protected][email protected],xxx代表邮件服务商
	 * @return 验证成功返回true,验证失败返回false ^ :匹配输入的开始位置。 \:将下一个字符标记为特殊字符或字面值。
	 *         :匹配前一个字符零次或几次。 + :匹配前一个字符一次或多次。 (pattern) 与模式匹配并记住匹配。 x|y:匹配 x 或
	 *         y。 [a-z] :表示某个范围内的字符。与指定区间内的任何字符匹配。 \w :与任何单词字符匹配,包括下划线。
	 * 
	 *         {n,m} 最少匹配 n 次且最多匹配 m 次 $ :匹配输入的结尾。
	 */
	public static boolean checkEmail(String email) {
    
    
		String regex = "^(\\w)+(\\.\\w+)*@(\\w)+((\\.\\w{2,3}){1,3})$";
		return Pattern.matches(regex, email);
	}

	/**
	 * 验证身份证号码
	 * 
	 * @param idCard
	 *            居民身份证号码15位或18位,最后一位可能是数字或字母
	 * @return 验证成功返回true,验证失败返回false
	 */
	public static boolean checkIdCard(String idCard) {
    
    
		String regex = "[1-9]\\d{13,16}[a-zA-Z0-9]{1}";
		return Pattern.matches(regex, idCard);
	}

	/**
	 * 验证手机号码(支持国际格式,+86135xxxx...(中国内地),+00852137xxxx...(中国香港))
	 * 
	 * @param mobile
	 *            移动、联通、电信运营商的号码段
	 *            <p>
	 *            移动的号段:134(0-8)、135、136、137、138、139、147(预计用于TD上网卡)
	 *            、150、151、152、157(TD专用)、158、159、187(未启用)、188(TD专用)
	 *            </p>
	 *            <p>
	 *            联通的号段:130、131、132、155、156(世界风专用)、185(未启用)、186(3g)
	 *            </p>
	 *            <p>
	 *            电信的号段:133、153、180(未启用)、189
	 *            </p>
	 *            <p>
	 *            虚拟运营商的号段:170
	 *            </p>
	 * @return 验证成功返回true,验证失败返回false
	 */
	public static boolean checkMobile(String mobile) {
    
    
		String regex = "(\\+\\d+)?1[34578]\\d{9}$";
		return Pattern.matches(regex, mobile);
	}

	/**
	 * 验证固定电话号码
	 * 
	 * @param phone
	 *            电话号码,格式:国家(地区)电话代码 + 区号(城市代码) + 电话号码,如:+8602085588447
	 *            <p>
	 *            <b>国家(地区) 代码 :</b>标识电话号码的国家(地区)的标准国家(地区)代码。它包含从 0 到 9
	 *            的一位或多位数字, 数字之后是空格分隔的国家(地区)代码。
	 *            </p>
	 *            <p>
	 *            <b>区号(城市代码):</b>这可能包含一个或多个从 0 到 9 的数字,地区或城市代码放在圆括号——
	 *            对不使用地区或城市代码的国家(地区),则省略该组件。
	 *            </p>
	 *            <p>
	 *            <b>电话号码:</b>这包含从 0 到 9 的一个或多个数字
	 *            </p>
	 * @return 验证成功返回true,验证失败返回false
	 */
	public static boolean checkPhone(String phone) {
    
    
		// String regex = "(\\+\\d+)?(\\d{3,4}\\-?)?\\d{7,8}$";
		String regex = "^1\\d{10}$";
		return Pattern.matches(regex, phone);
	}

	/**
	 * 验证整数(正整数和负整数)
	 * 
	 * @param digit
	 *            一位或多位0-9之间的整数
	 * @return 验证成功返回true,验证失败返回false
	 */
	public static boolean checkDigit(String digit) {
    
    
		String regex = "\\-?[1-9]\\d+";
		return Pattern.matches(regex, digit);
	}

	/**
	 * 验证整数和浮点数(正负整数和正负浮点数)
	 * 
	 * @param decimals
	 *            一位或多位0-9之间的浮点数,如:1.23,233.30
	 * @return 验证成功返回true,验证失败返回false
	 */
	public static boolean checkDecimals(String decimals) {
    
    
		String regex = "\\-?[1-9]\\d+(\\.\\d+)?";
		return Pattern.matches(regex, decimals);
	}

	/**
	 * 验证空白字符
	 * 
	 * @param blankSpace
	 *            空白字符,包括:空格、\t、\n、\r、\f、\x0B
	 * @return 验证成功返回true,验证失败返回false
	 */
	public static boolean checkBlankSpace(String blankSpace) {
    
    
		String regex = "\\s+";
		return Pattern.matches(regex, blankSpace);
	}

	/**
	 * 验证中文
	 * 
	 * @param chinese
	 *            中文字符
	 * @return 验证成功返回true,验证失败返回false
	 */
	public static boolean checkChinese(String chinese) {
    
    
		String regex = "^[\u4E00-\u9FA5]+$";
		return Pattern.matches(regex, chinese);
	}

	/**
	 * 验证日期(年月日)
	 * 
	 * @param birthday
	 *            日期,格式:1992-09-03,或1992.09.03
	 * @return 验证成功返回true,验证失败返回false
	 */
	public static boolean checkBirthday(String birthday) {
    
    
		String regex = "[1-9]{4}([-./])\\d{1,2}\\1\\d{1,2}";
		return Pattern.matches(regex, birthday);
	}

	/**
	 * 验证URL地址
	 * 
	 * @param url
	 *            格式:http://blog.csdn.net:80/xyang81/article/details/7705960? 或
	 *            http://www.csdn.net:80
	 * @return 验证成功返回true,验证失败返回false
	 */
	public static boolean checkURL(String url) {
    
    
		String regex = "(https?://(w{3}\\.)?)?\\w+\\.\\w+(\\.[a-zA-Z]+)*(:\\d{1,5})?(/\\w*)*(\\??(.+=.*)?(&.+=.*)?)?";
		return Pattern.matches(regex, url);
	}

	/**
	 * 匹配中国邮政编码
	 * 
	 * @param postcode
	 *            邮政编码
	 * @return 验证成功返回true,验证失败返回false
	 */
	public static boolean checkPostcode(String postcode) {
    
    
		String regex = "[1-9]\\d{5}";
		return Pattern.matches(regex, postcode);
	}

	/**
	 * 匹配IP地址(简单匹配,格式,如:192.168.1.1,127.0.0.1,没有匹配IP段的大小)
	 * 
	 * @param ipAddress
	 *            IPv4标准地址
	 * @return 验证成功返回true,验证失败返回false
	 */
	public static boolean checkIpAddress(String ipAddress) {
    
    
		String regex = "[1-9](\\d{1,2})?\\.(0|([1-9](\\d{1,2})?))\\.(0|([1-9](\\d{1,2})?))\\.(0|([1-9](\\d{1,2})?))";
		return Pattern.matches(regex, ipAddress);
	}

	public static boolean checkNickname(String nickname) {
    
    
		String regex = "^[a-zA-Z0-9\u4E00-\u9FA5_]+$";
		return Pattern.matches(regex, nickname);
	}
	

    public static boolean hasCrossSciptRiskInAddress(String str) {
    
    
        String regx = "[`~!@#$%^&*+=|{}':;',\\[\\].<>~!@#¥%……&*——+|{}【】‘;:”“’。,、?-]";
        if (str != null) {
    
    
            str = str.trim();
            Pattern p = Pattern.compile(regx, Pattern.CASE_INSENSITIVE);
            Matcher m = p.matcher(str);
            return m.find();
        }
        return false;
    }
}

4.1 Common regular expressions

Description: Regular expressions are commonly used for two tasks: 1. Validation, 2. Search/replace. When used for verification, it is usually necessary to add ^ and $ before and after to match the entire string to be verified; whether to add this limit when searching/replacing depends on the search requirements. In addition, it may also be necessary to add before and after \b instead of ^ and $. The commonly used regular expressions listed in this table are not preceded or followed by any restrictions except for a few. Please handle them by yourself according to your needs.

4.2 Expression of check digit

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})?$
7. 带1-2位小数的正数或负数:^(\-)?\d+(\.\d{1,2})?$
8. 正数、负数、和小数:^(\-|\+)?\d+(\.\d+)?$
9. 有两位小数的正实数:^[0-9]+(.[0-9]{2})?$
10. 有1~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)$

4.3 Expression of check character

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]+

4.4 Special Requirements Expressions

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]* 或 ^http://([\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-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}

7. 身份证号(15位、18位数字):^\d{15}|\d{18}$

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和1~12):^(0?[1-9]|1[0-2])$

14. 一个月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$

15. 钱的输入格式:

    i. 有四种钱的表示形式我们可以接受:"10000.00" 和 "10,000.00", 和没有 "分" 的 "10000" 和 "10,000":^[1-9][0-9]*$

    ii. 这表示任意一个不以0开头的数字,但是,这也意味着一个字符"0"不通过,所以我们采用下面的形式:^(0|[1-9][0-9]*)$

    iii. 一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号:^(0|-?[1-9][0-9]*)$

    iv. 这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧.下面我们要加的是说明可能的小数部分:^[0-9]+(.[0-9]+)?$

    v. 必须说明的是,小数点后面至少应该有1位数,所以"10."是不通过的,但是 "10" 和 "10.2" 是通过的:^[0-9]+(.[0-9]{2})?$

    vi. 这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:^[0-9]+(.[0-9]{1,2})?$

    vii. 这样就允许用户只写一位小数.下面我们该考虑数字中的逗号了,我们可以这样:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$

    viii. 1到3个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$

    备注:这就是最终结果了,别忘了"+"可以用"*"替代如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里

16. xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$

17. 中文字符的正则表达式:[\u4e00-\u9fa5]

18. 双字节字符:[^\x00-\xff] (包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))

19. 空白行的正则表达式:\n\s*\r (可以用来删除空白行)

20. HTML标记的正则表达式:<(\S*?)[^>]*>.*?</\1>|<.*? /> (网上流传的版本太糟糕,上面这个也仅仅能部分,对于复杂的嵌套标记依旧无能为力)

21. 首尾空白字符的正则表达式:^\s*|\s*$或(^\s*)|(\s*$) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)

22. 腾讯QQ号:[1-9][0-9]{4,} (腾讯QQ号从10000开始)

23. 中国邮政编码:[1-9]\d{5}(?!\d) (中国邮政编码为6位数字)

24. IP地址:\d+\.\d+\.\d+\.\d+ (提取IP地址时有用)

25. IP地址:((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))

Guess you like

Origin blog.csdn.net/qq_34988304/article/details/132313342