【Java从0到1学习】09 正则表达式

09 正则表达式

1. 正则表达式概述

在编写处理字符串的程序或网页时,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说,正则表达式就是记录文本规则的代码。

正则表达式,又称正规表示法、常规表示法(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些符合某个模式的文本

许多程序设计语言都支持利用正则表达式进行字符串操作。例如,在Perl中就内建了一个功能强大的正则表达式引擎。正则表达式这个概念最初是由Unix中的工具软件(例如sed和grep)普及开的。正则表达式通常缩写成“regex”,单数有regexp、regex,复数有regexps、regexes、regexen

正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑

1.1 正则表达式的目的

  • 给定的字符串是否符合正则表达式的过滤逻辑(称作“匹配”)
  • 可以通过正则表达式,从字符串中获取我们想要的特定部分

1.2 正则表达式的特点

  • 灵活性、逻辑性和功能性非常的强;
  • 可以迅速地用极简单的方式达到字符串的复杂控制。
  • 对于刚接触的人来说,比较晦涩难懂。

由于正则表达式主要应用对象是文本,因此它在各种文本编辑器场合都有应用,小到著名编辑器EditPlus,大到Microsoft Word、Visual Studio等大型编辑器,都可以使用正则表达式来处理文本内容

2. 正则表达式基础知识

2.1 元字符

正则表达式主要依赖于元字符。

元字符不代表他们本身的字面意思, 他们都有特殊的含义。 一些元字符写在方括号中的时候有一些特殊的意思。 以下是一些元字符的介绍:

元字符描述
.句号匹配任意单个字符除了换行符
[ ]字符种类. 匹配方括号内的任意字符
[^ ]否定的字符种类. 匹配除了方括号里的任意字符
*匹配>=0个重复的在*号之前的字符
+匹配>=1个重复的+号前的字符
?标记?之前的字符为可选
{n,m}匹配num个中括号之前的字符 (n <= num <= m)
(xyz)字符集, 匹配与 xyz 完全相等的字符串
|或运算符,匹配符号前或后的字符
\转义字符,用于匹配一些保留的字符 `[ ] ( ) { } . * + ? ^ $ \
^从开始行开始匹配
$从末端开始匹配

2.2 常见符号

2.2.1 字符

符号说明
X字符X
\\反斜线
\t制表符 (‘\u0009’)
\n回车
\r换行
\f换页符 (‘\u000C’)
\a报警 (bell) 符 (‘\u0007’)

2.2.2 字符类

符号说明
[abc]a、b或c
[^abc]任何字符,除了a、b或c
[a-zA-Z]a到z,或A到Z
[0-9]0到9的字符
[a-d[m-p]]a到 d或 m 到 p:[a-dm-p](并集)
[a-z&&[def]]d、e或 f(交集)
[a-z&&[^bc]]a到 z,除了 b和 c:[ad-z](减去)
[a-z&&[^m-p]]a到 z,而非 m到 p:[a-lq-z](减去)
\u4E00-\u9FA5中文字符

2.2.3 预定义字符

符号说明
.任何字符
\d数字:[0-9]
\D非数字: [^0-9]
\s空白字符:[ \t\n\x0B\f\r]
\S非空白字符:[^\s]
\w单词字符:[a-zA-Z_0-9]
\W非单词字符:[^\w]

2.3 中括号表达式

范围匹配,一种特殊的匹配单个字符的方法。

  • 即[ ]表达式,用来匹配单个字符,只不过这一个字符的所在范围有中括号内的表达式来确定
  • 枚举:[abc],表示匹配a、b、c的任意一个
  • 范围:[a-f],表示匹配a-f之间的任意一个字符,包括边界,其中右边界一定要≥左边界,否则引擎编译错误
  • 并:[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:定义邮箱的规则
 * 			1517806580@qq.com
 * 			liuyi@163.com
 * 			linqingxia@126.com
 * 			fengqingyang@sina.com.cn
 * 			fqy@itcast.cn
 * 		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对象,依照正则表达式,该对象可以与任意字符序列匹配。执行匹配所涉及的所有状态都驻留在匹配器中,所以多个匹配器可以共享同一模式

分组:简单的说,分组其实就是为了能够指定同一个规则可以使用多少次。正则表达式中的分组就是整个大的正则表达式和用()圈起来的内容。

在这个正则表达式"\w(\d\d)(\w+)"中

  • 分组0:是"\w(\d\d)(\w+)"
  • 分组1:是(\d\d)
  • 分组2:是(\w+)

如果我们稍稍变换一下,将原先的正则表达式改为"(\w)(\d\d)(\w+)",我们的分组就变成了

  • 分组0:是"\w(\d\d)(\w+)"
  • 分组1:是"(\w)"
  • 分组2:是"(\d\d)"
  • 分组3:是"(\w+)"

我们看看和正则表达式”\w(\d\d)(\w+)”匹配的一个字符串A22happy

  • group(0)是匹配整个表达式的字符串的那部分A22happy
  • group(1)是第1组(\d\d)匹配的部分:22
  • group(2)是第2组(\w+)匹配的那部分happy
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));
	    }
	}
}
  • start()方法的使用
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);        
}

运行结果:

/**
  * 测试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()));
}

运行结果:

  • 获取由三个字符组成的单词
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);
	}
}
  • 判断身份证:要么是15位,要么是18位,最后一位可以为字母,并写程序提出其中的年月日。
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));

            }
        }
    }
}

运行结果:

4. 正则表达式工具类

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

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

	/**
	 * 验证Email
	 * 
	 * @param email
	 *            email地址,格式:zhangsan@sina.com,zhangsan@xxx.com.cn,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 常用正则表达式

说明:正则表达式通常用于两种任务:1.验证,2.搜索/替换。用于验证时,通常需要在前后分别加上^和$,以匹配整个待验证字符串;搜索/替换时是否加上此限定则根据搜索的要求而定,此外,也有可能要在前后加上\b而不是^和$。此表所列的常用正则表达式,除个别外均未在前后加上任何限定,请根据需要,自行处理。

4.2 校验数字的表达式

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 校验字符的表达式

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 特殊需求表达式

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))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/81895.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MybatisPlus整合p6spy组件SQL分析

目录 p6spy java为什么需要 如何使用 其他配置 p6spy p6spy是一个开源项目&#xff0c;通常使用它来跟踪数据库操作&#xff0c;查看程序运行过程中执行的sql语句。 p6spy将应用的数据源给劫持了&#xff0c;应用操作数据库其实在调用p6spy的数据源&#xff0c;p6spy劫持到…

2023最新版本~KEIL5使用C++开发STM32

先看效果 开始教学 因为是第一次写这个配置教程 我会尽量详细些 打开一个Keil工程 移除本地core 添加在线core 第一次编译代码 不会有报错 修改main.c文件类型为C 点击魔术棒 把ARM编译器修改为V6 第二次编译会报错语法不兼容 我把汇编部分的这些代码做了…

安防视频汇聚平台EasyCVR视频监控综合管理平台H.265转码功能更新,新增分辨率配置的具体步骤

安防视频集中存储EasyCVR视频监控综合管理平台可以根据不同的场景需求&#xff0c;让平台在内网、专网、VPN、广域网、互联网等各种环境下进行音视频的采集、接入与多端分发。在视频能力上&#xff0c;视频云存储平台EasyCVR可实现视频实时直播、云端录像、视频云存储、视频存储…

【idea】社区版idea运行Tomcat

使用 Smart Tomcat插件 配置运行&#xff1a;

vue导出文件流获取附件名称并下载(在response.headers里解析filename导出)

导出文件流下载&#xff0c;拦截器统一处理配置 需求以往实现的方法&#xff08;各自的业务层写方法&#xff09;现在实现的方法&#xff08;axios里拦截器统一配置处理&#xff09;把文章链接复制粘贴给后端&#xff0c;让大佬自己赏阅。 需求 之前实现的导出都是各自的业务层…

网络编程(字节序)

一、字节序的概念 字节序是指不同类型CPU主机&#xff0c;内存存储 多字节整数 序列的方式。 float, char, 字符串均没有字节序的说法 short, int , long , long long 有字节序的说法 小端字节序&#xff1a;低字节存储在低地址&#xff0c;高字节存储在高地址 大端字节序…

常见架构类型

目录 1.单机架构 2.应用数据分离架构 3.读写分离架构 4.冷热分离架构 5.垂直分库架构 6.微服务架构 7.容器编排架构 1.单机架构 单机架构是简单的将应用服务和数据库服务部署到同一台机器上。 缺点&#xff1a;存在很大的性能限制。 2.应用数据分离架构 引入负载均衡&a…

vue3+elementPlus table里添加输入框并提交校验

<template><div><el-form :model"info" ref"forms"><el-tableref"tableRef":data"info.data"border><el-table-column align"center" property"name" label"*姓名"><…

mapper.xml中循环执行多条语句时报错,但是单独拿SQL到数据库却可以执行

我是批量修改数据&#xff0c;用foreach标签包住update语句&#xff0c;报错信息如下&#xff1a; nested exception is java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the …

Dubbo 融合 Nacos 成为注册中心

快速上手 Dubbo 融合 Nacos 成为注册中心的操作步骤非常简单&#xff0c;大致步骤可分为“增加 Maven 依赖”以及“配置注册中心“。 增加 Maven 依赖 只需要依赖Dubbo客户端即可&#xff0c;关于推荐的使用版本&#xff0c;请参考Dubbo官方文档或者咨询Dubbo开发人员&#…

vite打包遇到的错误

1.js emit is not supported 2.将package.json中的bulid后面写成“vue-tsc --noEmit --skipLibCheck && vite build” 3.再次打包成功

微信程序 自定义遮罩层遮不住底部tabbar解决

一、先上效果 二 方法 1、自定义底部tabbar 实现&#xff1a; https://developers.weixin.qq.com/miniprogram/dev/framework/ability/custom-tabbar.html 官网去抄 简单写下&#xff1a;在代码根目录下添加入口文件 除了js 文件的list 需要调整 其他原封不动 代码&#xf…

RT1052的EPWM

文章目录 1 EPWM介绍1.1 引脚1.2 时钟1.3 比较寄存器 2 函数 1 EPWM介绍 RT1052 具有 4 个 eFlexPWM(eFlexWM1~eFlex_PWM4)。 每个 eFlexPWM 可以产生四路互补 PWM即产生 8 个 PWM&#xff0c;也可以产生相互独立的 PWM 波。四路分别是模块0-3每个 eFlexPWM 具有各自的故障检…

opencv进阶09-视频处理cv2.VideoCapture示例(打开本机电脑摄像头)

视频信号&#xff08;以下简称为视频&#xff09;是非常重要的视觉信息来源&#xff0c;它是视觉处理过程中经常要处理的一类信号。实际上&#xff0c;视频是由一系列图像构成的&#xff0c;这一系列图像被称为帧&#xff0c;帧是以固定的时间间隔从视频中获取的。获取&#xf…

react之路由的安装与使用

一、路由安装 路由官网2021.11月初&#xff0c;react-router 更新到 v6 版本。使用最广泛的 v5 版本的使用 npm i react-router-dom5.3.0二、路由使用 2.1 路由的简单使用 第一步 在根目录下 创建 views 文件夹 ,用于放置路由页面 films.js示例代码 export default functio…

如何在前端实现WebSocket发送和接收UDP消息(多线程模式)

目录 简介&#xff1a;步骤1&#xff1a;创建WebSocket连接步骤2&#xff1a;创建Web Workers步骤3&#xff1a;发送和接收UDP消息&#xff08;多线程模式&#xff09;结束语&#xff1a; 简介&#xff1a; 本文将继续介绍如何在前端应用中利用WebSocket技术发送和接收UDP消息…

C#生产流程控制(串行,并行混合执行)

开源框架CsGo https://gitee.com/hamasm/CsGo?_fromgitee_search 文档资料&#xff1a; https://blog.csdn.net/aa2528877987/article/details/132139337 实现效果 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…

vue 关闭prettier警告warn

这个就是我们创建vue cli的时候 把这个给默认上了 关闭这个只需在.eslintrc.js页面里边添加一行代码"prettier/prettier": "off"

从零开始创建 Spring Cloud 分布式项目,不会你打我

目录 一、Spring Cloud 和 分布式 二、创建新项目 三、导入 Spring Cloud 依赖 四、配置 Spring Cloud 一、Spring Cloud 和 分布式 Spring Cloud是一个基于Spring框架的开源微服务框架&#xff0c;它提供了一系列工具和组件&#xff0c;用于帮助开发人员构建分布式系统中…

(学习笔记-进程管理)什么是悲观锁、乐观锁?

互斥锁与自旋锁 最底层的两种就是 [互斥锁和自旋锁]&#xff0c;有很多高级的锁都是基于它们实现的。可以认为它们是各种锁的地基&#xff0c;所以我们必须清楚它们之间的区别和应用。 加锁的目的就是保证共享资源在任意时间内&#xff0c;只有一个线程访问&#xff0c;这样就…