Java学习(二十二)--正则表达式

介绍

为什么需要

    正则表达式是处理文本的利器;

基本介绍

    正则表达式,又称规则表达式,(Regular Expression,在代码中常简写为regex、regexp或RE)。它是一个强大的字符串处理工具,可以对字符串进行查找、提取、分割、替换等操作,是一种可以用于模式匹配和替换的规范;

    一个正则表达式就是由普通的字符(如字符 a~z)以及特殊字符(元字符)组成的文字模式,用以描述在查找文字主体时待匹配的一个或多个字符串。

    jdk1.4推出 java.util.regex 包,它包含了 Pattern 和 Matcher 类,用于处理正则表达式的匹配操作。

package com.lhy.regex;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发布" ;//目标:匹配所有四个数字//说明//1. \\d 表示一个任意的数字String regStr = "(\\d\\d)(\\d\\d)";//2. 创建一个模式对象[即正则表达式对象]Pattern pattern = Pattern.compile(regStr);//3. 创建一个匹配器对象//说明:创建匹配器matcher, 按照 正则表达式的规则(pattern模式) 去匹配 content字符串Matcher matcher = pattern.matcher(content);//4.开始循环匹配while (matcher.find()) {//小结//1. 如果正则表达式有() 即分组//2. 取出匹配的字符串规则如下//3. group(0) 表示匹配到的子字符串//4. group(1) 表示匹配到的子字符串的第一组字串//5. group(2) 表示匹配到的子字符串的第2组字串//6. ... 但是分组的数不能越界.System.out.println("找到: " + matcher.group(0));//找到: 1998System.out.println("第1组()匹配到的值=" + matcher.group(1));//19System.out.println("第2组()匹配到的值=" + matcher.group(2));//98}}
}

语法

\\符号说明:在我们使用正则表达式去检索某些特殊字符的时候,需要用到转义字符,否则检测不到结果,甚至会报错。

注意:在Java的正则表达式中,两个\\代表其他语言中的一个\;

元字符

限定符

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

符号含义示例说明匹配输入
*指定字符重复0次或n次(无要求)零到多(abc)*仅包含任意个abc的字符串,等效于\w*abc、 abcabcabc
+指定字符重复1次或n次(至少 一次)1到多m+(abc)*以至少1个m开头,后接任意个abc的字 符串m、mabc、 mabcabc
?指定字符重复0次或1次(最多 一次)0到1m+abc?以至少1个m开头,后接ab或abc的字符 串mab、mabc、mmmab. mmabc
{}只能输入n个字符[abcd]{3}由abcd中字母组成的任意长度为3的字 符串abc、dbc、adc
{n,}指定至少n个匹配[abcd]{3,}由abcd中字母组成的任意长度不小于3的字符串aab、dbc、aaabdc
{n,m}指定至少n个但不多于m个匹配[abcd]{3,5}由abcd中字母组成的任意长度不小于3,不大于5的字符串abc、abcd、aaaaa、bcdab

java默认为贪婪匹配

  • 即:在限定出现次数里,优先匹配出现次数最多的一组。
  • 例如:用a{3,5}来匹配aaaaaacx,返回的式aaaaa。
  • 例如:a.*b,它将会匹配最长的以a开始,以b结束的字符串。如果用它来搜索aabab的
    话,它会匹配整个字符串aaba。

?组合的时候,它只作用于离他最近的那一个字符。

  • 例如:m+abc?中,?只作用于字符c。

如果想要使用非贪婪匹配(懒惰匹配),则在限定符后面加上?即可。

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


选择匹配符

在匹配某个字符串的时候是选择性的,即可以匹配这个,也可以匹配那个。

符号
符号示例解释
|匹配“|”之前或之后的表达式ab|cdab或者cd

 


分组组合和反向引用符

1、分组

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

2、捕获分组

  •  把正则表达式中子表达式或分组匹配的内容,保存到内存中以数字编号或显式命名的组里,方便后面引用,从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。组0代表的是整个正则式。
常用分组构造形式说明
(pattern)非命名捕获。捕获匹配的子字符串。编号为零的第一个捕获是由整个正则表达式模式匹配的文本,其它捕获结果则根据左括号的顺序从1开始自动编号。(在分析底层源码的时候说过)
(?pattern)命名捕获。将匹配的子字符串捕获到一个组名称或编号名称中。用于name的字符串不能包括任何标点符号,并且不能以数字开头。可以使用单引号替代尖括号,例如(?`name`)

 

String test = "020-85653333";
String reg="(0\\d{2})-(\\d{8})";
Pattern pattern = Pattern.compile(reg);
Matcher mc= pattern.matcher(test);
if(mc.find()){System.out.println("分组的个数有:"+mc.groupCount());for(int i=0;i<=mc.groupCount();i++){System.out.println("第"+i+"个分组为:"+mc.group(i));}
}
输出结果:分组的个数有:2
第0个分组为:020-85653333
第1个分组为:020
第2个分组为:85653333

 

String test = "020-85653333";
String reg="(?<quhao>0\\d{2})-(?<haoma>\\d{8})";
Pattern pattern = Pattern.compile(reg);
Matcher mc= pattern.matcher(test);
if(mc.find()){System.out.println("分组的个数有:"+mc.groupCount());System.out.println(mc.group("quhao"));System.out.println(mc.group("haoma"));
}
输出结果:分组的个数有:2
分组名称为:quhao,匹配内容为:020
分组名称为:haoma,匹配内容为:85653333

3、非捕获分组

常用分组构造形式说明
(?:pattern)匹配pattern但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储以后使用的匹配。这对于用“or”字符(|)组合模式部件的情况很有用。例如:`industr(?:y
(?=pattern)它是一个非捕获匹配。例如:`windows(?=95
(?!pattern)该表达式匹配不处于匹配pattern的字符串的起始点的搜索字符串。它是一个非捕获匹配。例如:`windows(?!95

 

String test = "020-85653333";
String reg="(?:0\\d{2})-(\\d{8})";
Pattern pattern = Pattern.compile(reg);
Matcher mc= pattern.matcher(test);
if(mc.find()){System.out.println("分组的个数有:"+mc.groupCount());for(int i=0;i<=mc.groupCount();i++){System.out.println("第"+i+"个分组为:"+mc.group(i));}
}
输出结果:分组的个数有:1
第0个分组为:020-85653333
第1个分组为:85653333
//正向先行断言
零宽度正预测先行断言语法:(?=pattern)作用:匹配pattern表达式的前面内容,不返回本身。【正向先行断言】可以匹配表达式前面的内容,那意思就是(?=) 就可以匹配到前面的内容了。@Test
public void testAssert1(){String regex = ".+(?=</span>)";String context = "<span class=\"read-count\">阅读数:641</span>";Pattern pattern = Pattern.compile(regex);Matcher matcher = pattern.matcher(context);while (matcher.find()){System.out.println(matcher.group());}
}//匹配结果:<span class="read-count">阅读数:641
//可是我们要的只是前面的数字呀,那也简单咯,匹配数字 \d,那可以改成:@Test
public void testAssert2(){String regex = "\\d+(?=</span>)";String context = "<span class=\"read-count\">阅读数:641</span>";Pattern pattern = Pattern.compile(regex);Matcher matcher = pattern.matcher(context);while (matcher.find()){System.out.println(matcher.group());}
}//匹配结果:
//641

4、反向引用

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

public class RegTheory {public static void main(String[] args) {String content = "123-abc";String regStr = "(?<i1>\\d)(?<i2>\\d)";Pattern pattern = Pattern.compile(regStr);Matcher matcher = pattern.matcher(content);while (matcher.find()){System.out.println(matcher.group("i1"));System.out.println(matcher.group("i2"));}}
}
// 结果是1,2

 

正向后行断言:零宽度正回顾后发断言,断言在前,模式在后语法:(?<=pattern)作用:匹配pattern表达式的后面的内容,不返回本身。有先行就有后行,先行是匹配前面的内容,那后行就是匹配后面的内容啦。@Test
public void testAssert3(){String regex = "(?<=<span class=\"read-count\">阅读数:)\\d+";String context = "<span class=\"read-count\">阅读数:641</span>";Pattern pattern = Pattern.compile(regex);Matcher matcher = pattern.matcher(context);while (matcher.find()){System.out.println(matcher.group());}
}
@Test
public void testRef(){String context = "aabbxxccdddsksdhfhshh";String regex = "(\\w)\\1";Pattern pattern = Pattern.compile(regex);Matcher matcher = pattern.matcher(context);while (matcher.find()){System.out.println(matcher.group());}
}
输出结果:aa
bb
xx
cc
dd
hh

 

//请编写一个 Servlet, 可以获取到浏览器所在电脑的操作系统版本和位数(32 还是 64), 显示在页面即可。
//(User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/112.0)public class ComputerServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req,resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String user_agent = req.getHeader("User-Agent");//1.匹配目标String regStr = "\\((.*)\\)";//2. 创建一个模式对象[即正则表达式对象]Pattern pattern = Pattern.compile(regStr);//3. 创建一个匹配器对象//说明:创建匹配器matcher, 按照 正则表达式的规则(pattern模式) 去匹配 content字符串Matcher matcher = pattern.matcher(user_agent);//4.开始循环匹配while (matcher.find()) {//匹配内容,放在 matcher.group(0);String group01 = matcher.group(1);String[] split = group01.split(";");System.out.println("操作系统=" +split[0]);//Windows NT 10.0System.out.println("操作系统位数=" + split[1].trim());// Win64}}
}

特殊字符--转义符

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


字符匹配符

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

定位符

规定要匹配的字符串出现的位置, 比如在字符串的开始还是在结束的位置。
符号含义示例说明匹配输入
^指定起始字符^[0-9]+[a-z]*以至少1个数字开头,后接任意个小写字 母的字符串123、6aa、555edf
$指定结束字符^[0-9]\\-[a-z]+$以1个数字开头后接连字符“-”,并以至少1个小写字母结尾的字符串1-a
\\b匹配目标字符串的边界han\\b这里说的字符串的边界指的是子串间有空格,或者是目标字符串的结束位置hanshunping sphan nnhan
\\B匹配目标字符串的非边界han\\B和b的含义刚刚相反hanshunping sphan nr

其他

java正则表达式默认是区分字母的大小写。如何实现不区分大小写的方式❓

  • 方式一:在需要不区分大小写的表达式前面写上(?i)。但需要注意的是,如果是表达式中间的某个字符不区分大小写的时候需要将它们括起来,例如:a((?i)b)c。
  • 方式二:Pattern pat = Pattern.compile(regEx,Pattern.CASE_INSENSITIVE);

常用类

Pattern 类(模式类):

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

Pattern 类没有公共构造方法;首先调用其公共静态编译方法,可返回一个 Pattern 对象, 该方法接受一个正则表达式作为它的第一个参数;,比如:Pattern r = Pattern.compile(pattem)

String content = "hello helloasdas";String regStr = "hello";Pattern pattern = Pattern.compile(regStr);Matcher matcher = pattern.matcher(content);while (matcher.find()){System.out.println(matcher.group(0));// 部分匹配,这里会匹配到两个hello} boolean matches = Pattern.matches(regStr, content);System.out.println(matches);// 这是false,因为它是整体匹配,即正则表达式去匹配整个字符;表示字符串完全符合给出的正则表达式所表示的范围。只要有一个字符不匹配则返回false串。//matches()的底层也只是封装了find()方法。

Matcher 类(匹配器类):

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

Macher类的常用方法

索引方法
序号方法说明
1public int start()返回以前匹配的初始索引。
2public int start(int group) 返回在以前的匹配操作期间,由给定组所捕获的子序列的初始索引
3public int end()返回最后匹配字符之后的偏移量。
4public int end(int group)返回在以前的匹配操作期间,由给定组所捕获子序列的最后字符之后的偏移量。
Pattern p=Pattern.compile("\\d+"); 
Matcher m=p.matcher("aaa2223bb"); 
m.find();//匹配2223 
m.start();//返回3 
m.end();//返回7,返回的是2223后的索引号 
m.group();//返回2223 Mathcer m2=m.matcher("2223bb"); 
m.lookingAt();   //匹配2223 
m.start();   //返回0,由于lookingAt()只能匹配前面的字符串,所以当使用lookingAt()匹配时,start()方法总是返回0 
m.end();   //返回4 
m.group();   //返回2223 Matcher m3=m.matcher("2223bb"); 
m.matches();   //匹配整个字符串 
m.start();   //返回0,原因相信大家也清楚了 
m.end();   //返回6,原因相信大家也清楚了,因为matches()需要匹配所有字符串 
m.group();   //返回2223bbPattern p=Pattern.compile("([a-z]+)(\\d+)"); 
Matcher m=p.matcher("aaa2223bb"); 
m.find();   //匹配aaa2223 
m.groupCount();   //返回2,因为有2组 
m.start(1);   //返回0 返回第一组匹配到的子字符串在字符串中的索引号 
m.start(2);   //返回3 
m.end(1);   //返回3 返回第一组匹配到的子字符串的最后一个字符在字符串中的索引位置. 
m.end(2);   //返回7 
m.group(1);   //返回aaa,返回第一组匹配到的子字符串 
m.group(2);   //返回2223,返回第二组匹配到的子字符串
查找方法
序号方法说明
1public boolean lookingAt() 尝试将从区域开头开始的输入序列与该模式匹配。
2public boolean find()尝试查找与该模式匹配的输入序列的下一个子序列。
3public boolean find(int start)重置此匹配器,然后尝试查找匹配该模式、从指定索引开始的输入序列的下一个子序列。
4public boolean matches()尝试将整个区域与模式匹配。

 

@Test
public void testMatches() {String regex = "Mary";String content1 = "Mary";String content2 = "Mary is very handsome  !";String content3 = "My name is Mary.";Pattern pattern = Pattern.compile(regex);Matcher matcher1 = pattern.matcher(content1);Matcher matcher2 = pattern.matcher(content2);Matcher matcher3 = pattern.matcher(content3);System.out.println("matches1(): " + matcher1.matches());System.out.println("lookingAt1(): " + matcher1.lookingAt());System.out.println("matches2(): " + matcher2.matches());System.out.println("lookingAt2(): " + matcher2.lookingAt());System.out.println("matches3(): " + matcher3.matches());System.out.println("lookingAt3(): " + matcher3.lookingAt());
}结果:
matches(): true
lookingAt(): true
matches(): false
lookingAt(): true
matches(): false
lookingAt(): false
//现在我们使用一下稍微高级点的正则匹配操作,例如有一段文本,里面有很多数字,而且这些数字是分开的,我们现在要将文本中所有数字都取出来,利用java的正则操作是那么的简单. Pattern p=Pattern.compile("\\d+"); 
Matcher m=p.matcher("我的QQ是:456456 我的电话是:0532214 我的邮箱是:aaa123@aaa.com"); 
while(m.find()) { System.out.println(m.group()); 
} 输出: 456456 
0532214 
123 package com.lhy.regex;import java.util.regex.Matcher;
import java.util.regex.Pattern;public class regex02 {public static void main(String[] args) {Pattern p=Pattern.compile("\\d+");Matcher m=p.matcher("我的QQ是:456456 我的电话是:0532214 我的邮箱是:aaa123@aaa.com");while(m.find()) {System.out.println(m.group());System.out.print("start:"+m.start());System.out.println(" end:"+m.end());}}
}则输出: 456456 
start:6 end:12 
0532214 
start:19 end:26 
123 
start:36 end:39 

每次执行匹配操作后start(),end(),group()三个方法的值都会改变,改变成匹配到的子字符串的信息,以及它们的重载方法,也会改变成相应的信息. 
注意:只有当匹配操作成功,才可以使用start(),end(),group()三个方法,否则会抛出java.lang.IllegalStateException,也就是当matches(),lookingAt(),find()其中任意一个方法返回true时,才可以使用. 

替换方法
序号方法说明
1public Matcher appendReplacement(StringBuffer sb, String replacement)实现非终端添加和替换步骤。
2public StringBuffer appendTail(StringBuffer sb)实现终端添加和替换步骤。
3public String replaceAll(String replacement) 替换模式与给定替换字符串相匹配的输入序列的每个子序列。
4public String replaceFirst(String replacement) 替换模式与给定替换字符串匹配的输入序列的第一个子序列。
5public static String quoteReplacement(String s)返回指定字符串的字面替换字符串。这个方法返回一个字符串,就像传递给Matcher类的appendReplacement 方法一个字面字符串一样工作。
@Test
public void testReplace(){String regex = "Mary";String context = "My name is Mary, Mary is very handsome. ";String replacement = "Lucy";Pattern p = Pattern.compile(regex);Matcher m = p.matcher(context);String result1 = m.replaceAll(replacement);System.out.println(result1);String result2 = m.replaceFirst(replacement);System.out.println(result2);
}结果:
My name is Lucy, itlils is very handsome. 
My name is Lucy, itnanls is very handsome. 

 

@Test
public void testAppend() {String REGEX = "a*b";String INPUT = "aabfooaabfooabfooabkkk";String REPLACE = "-";Pattern p = Pattern.compile(REGEX);// 获取 matcher 对象Matcher m = p.matcher(INPUT);StringBuffer sb = new StringBuffer();m.find();m.appendReplacement(sb, REPLACE);System.out.println(sb);m.find();m.appendReplacement(sb, REPLACE);System.out.println(sb);m.appendTail(sb);System.out.println(sb);
}结果:
-
-foo-
-foo-fooabfooabkkk

PatternSyntaxException:

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


其他

String类中使用正则表达式的方法

方法返回类型功能示例
matches()boolean告知此字符串是否匹配给定的正则表达式。"-1234".matches("^-?\\d+$") => true
replaceAll(String regex, String replacement)String使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。"a1b2c3".replaceAll("[a-zA-z]", "") => 123
replaceFirst(String regex, String replacement)String使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。"Hello World! Hello Everyone!".replaceFirst("\\s", "") => HelloWorld! Hello Everyone!
split(String regex)String[]根据给定正则表达式的匹配拆分此字符串。"boo:and:foo".split(":") => { "boo", "and", "foo" }
split(String regex, int limit)String[]根据给定正则表达式的匹配拆分此字符串。"boo:and:foo".split(":", 5) => { "boo", "and", "foo" }

split(String regex, int limit)方法中limit 参数控制模式应用的次数,因此影响所得数组的长度。

  • 如果该限制 n 大于 0,则模式将被最多应用 n - 1 次,数组的长度将不会大于 n,而且数组的最后一项将包含所有超出最后匹配的定界符的输入。
  • 如果 n 为非正,那么模式将被应用尽可能多的次数,而且数组可以是任何长度。
  • 如果 n 为 0,那么模式将被应用尽可能多的次数,数组可以是任何长度,并且结尾空字符串将被丢弃。
  • 例如,字符串 "boo:and:foo" 使用这些参数可生成以下结果:
RegexLimit结果
:2{ "boo", "and:foo" }
:5{ "boo", "and", "foo" }
:-2{ "boo", "and", "foo" }
o5{ "b", "", ":and:f", "", "" }
o-2{ "b", "", ":and:f", "", "" }
o0{ "b", "", ":and:f" }

调用此方法的 str.split(regex, n) 形式与以下表达式产生的结果完全相同:Pattern.compile(regex).split(str, n) 

String content = "hello helloasdas";
String str = content.replaceAll("(\\w)\\1+", "$1");
System.out.println(str); // 结果helo heloasdas	String content = "hehllos";
String regex = "^(h)\\w*s$";	
boolean matches = content.matches("^(h)\\w*s$");
System.out.println(matches); //结果 trueString content = "hehllos";
String[] hs = content.split("h");
for (String h : hs) {System.out.println(h);
} // 结果: e	llos

常用正则表达式

校验数字的表达式

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


校验字符的表达式

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-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}

7 身份证号:
15或18位身份证:^\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和1~12):^(0?[1-9]|1[0-2])$

14 一个月的31天(01~09和1~31):^((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.1到3个数字,后面跟着任意个 逗号+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地址时有用)


应用案例

//将一个文件中的电话的中间四个数字替换成xxxx? 例子 15236985456 --> 152xxxx5456姓名      年龄      邮箱                   电话
张小强    23    526845845@163.com     13759685424
丁新新    20    238011792@qq.com      18011023709
李银龙    20    liyinl1199w@163.com   17308811441
赵资本    19    anhuo69579@126.com    18234417225
李成刚    21    19713318@qq.com       13279906620
王铁柱    20    ykl3987671@163.com    18802836971
张龙虎    22    zh199715@gmail.com    13888906654
李洁一    18    nl897665@yahoo.com    19762297581
刘大志    20    197685551@qq.com      15299744196
杨天天    19    86765ytian@126.com    17663999002
陈承成    21    rr796232@hotmail.com  18137541864@Test
public void hidePhoneNumber() throws IOException {StringBuilder sb = new StringBuilder();// 1、将文件的内容读取到内存InputStream in = new FileInputStream("D:\\user.txt");byte[] buf = new byte[1024];int len;while ((len = in.read(buf)) > 0){sb.append(new String(buf,0,len));}// 2、进行正则匹配String regex = "(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])(\\d{4})(\\d{4})";Pattern pattern = Pattern.compile(regex);Matcher matcher = pattern.matcher(sb.toString());String result = matcher.replaceAll("$1xxxx$3");System.out.println(result);}
//通过scanner输入一个字符串,判断是否是一个邮箱?public class TestEmail {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);String email = scanner.next();String regex = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$";Pattern pattern = Pattern.compile(regex);Matcher matcher = pattern.matcher(email);boolean matches = matcher.matches();if(matches){System.out.println("您输入的是一个邮箱!");} else {System.out.println("您输入的不是邮箱!");}}
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

语音模块学习——LSYT201B模组(深圳雷龙科技)

目录 引子 处理器 外设 音频 蓝牙 模组展示 引子 关注我的老粉们应该知道我之前用过语音模块做东西&#xff0c;那个比较贵要50多。 今天这个淘宝20元左右比那个便宜&#xff0c;之前那个内核是51的&#xff0c;一个8位机。 后面我做东西的时候语音模块可能会换成这个&…

【计算机网络】Socket的TCP_NODELAY选项与Nagle算法

TCP_NODELAY是一个套接字选项&#xff0c;用于控制TCP套接字的延迟行为。当TCP_NODELAY选项被启用时&#xff0c;即设置为true&#xff0c;就会禁用Nagle算法&#xff0c;从而实现TCP套接字的无延迟传输。这意味着每次发送数据时都会立即发送&#xff0c;不会等待缓冲区的填充或…

代码随想录算法训练营DAY24|回溯1

算法训练DAY24|回溯1 第77题. 组合 力扣题目链接 给定两个整数 n 和 k&#xff0c;返回 1 ... n 中所有可能的 k 个数的组合。 示例: 输入: n 4, k 2 输出: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ] 上面我们说了要解决 n为100&#xff0c;k为50的情况&#xff0…

vscode连不上虚拟机,一直密码错误

最近在做毕设&#xff0c;但是vscode使用连接不上虚拟机&#xff0c;我以为是网络配置的问题&#xff0c;一顿查阅没找到原因。 后来查了一下ssh的日志&#xff0c;发现ssh有消息&#xff0c;但是也提示密码错误。 没找到密码配置格式什么的&#xff0c;经查看sshd配置文件发现…

DLL注入技术

源地址 注入程序 #include <Windows.h> #include <iostream> #include <Tlhelp32.h> #include <stdio.h> #include <tchar.h> #include <iostream>using namespace std;BOOL getProcess32Info(PROCESSENTRY32 *info, const TCHAR proces…

Go语言的映射reflect使用大全

目录 前言 一、映射的基本用法 1.获取类型信息 2.获取值 3.读取和设置值 4.使用Kind来区分类型 5.操作结构体 6.创建新实例 7.调用方法 8.调用方法 二、使用实例 总结 前言 Go语言作为一个高性能的静态语言&#xff0c;我们在写函数的时候&#xff0c;由于go语言的特性&#x…

工业相机与镜头参数及选型

文章目录 1、相机成像系统模型1.1 视场1.2 成像简化模型 2、工业相机参数2.1 分辨率2.2 靶面尺寸2.3 像元尺寸2.4 帧率/行频2.5 像素深度2.6 动态范围2.7 信噪比2.8 曝光时间2.9 相机接口 3、工业镜头参数3.1 焦距3.2 光圈3.3 景深3.4 镜头分辨率3.5 工作距离&#xff08;Worki…

微信小程序入门,学习全局配置与页面配置

目录 一、微信小程序 二、微信小程序的全局配置 三、微信小程序的页面配置 四、全局配置与页面配置的区别 一、微信小程序 微信小程序是一种基于微信平台的应用程序&#xff0c;它可以在微信内部直接运行&#xff0c;无需下载安装。微信小程序具有以下特点和优势&#xff…

Spring Boot自动配置原理

1.SpringBootApplication注解 springboot是基于spring的新型的轻量级框架&#xff0c;最厉害的地方当属**自动配置。**那我们就可以根据启动流程和相关原理来看看&#xff0c;如何实现传奇的自动配置 SpringBootApplication//标注在某个类上&#xff0c;表示这个类是SpringBo…

【技术预研】starRocks高性价比替换hbase

hbase作为类列数据库&#xff0c;更准确说是列族数据库。本质上是一个文件查询系统&#xff0c;追求极限的写入和读取。 而starRocks作为olap数据库&#xff0c;在保持优秀的关联计算能力的前提下&#xff0c;还有不错的查询效率&#xff0c;当然和hbase本身比还有一定差距。 但…

<蓝桥杯软件赛>零基础备赛20周--第15周--快速幂+素数

报名明年4月蓝桥杯软件赛的同学们&#xff0c;如果你是大一零基础&#xff0c;目前懵懂中&#xff0c;不知该怎么办&#xff0c;可以看看本博客系列&#xff1a;备赛20周合集 20周的完整安排请点击&#xff1a;20周计划 每周发1个博客&#xff0c;共20周。 在QQ群上交流答疑&am…

【设计模式】张一鸣笔记:责任链接模式怎么用?

我将通过一个贴近现实的故事——请假审批流程&#xff0c;带你了解和掌握责任链模式。 什么是责任链模式&#xff1f; 责任链模式是一种行为设计模式&#xff0c;它让你可以避免将请求的发送者与接收者耦合在一起&#xff0c;让多个对象都有处理请求的机会将这个对象连成一条…

python基础教程九 抽象二(函数参数)

1. 值从哪里来 定义函数时&#xff0c;你可能心存疑虑&#xff0c;参数的值是怎么来的呢&#xff1f; 在def语句中&#xff0c;位于函数名后面的变量通常称为形式参数&#xff0c;在调用函数时提供的值称为实参&#xff0c;但在本书不做严格区分。 2. 我能修改参数吗 函数通…

同样是IT行业,测试和开发薪资真就差这么大吗?

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

Java进阶之旅第六天

Java进阶之旅第六天 Stream流 Stream的思想 Stream流中引入函数式编程的思想,以类似流水线的方式处理数据,使得代码更加高效整洁Stream中提供并行处理的能力,可以将数据分成多个子任务,并行处理 各类型的调用方法 类型方法说明单列集合default Stream streamCollection中默…

请写出js中的两种定时器,区别是什么?怎么清除定时器?

在JavaScript中有两种常用的定时器&#xff1a;setTimeout 和 setInterval。 setTimeout&#xff1a;此函数用于在指定的毫秒数后执行一次函数或计算出的表达式。例如&#xff0c;如果你想在5秒后打印一条消息&#xff0c;你可以这样做&#xff1a; var myTimer setTimeout(f…

下载csdn文章,并保存md笔记中的图片链接至本地

推荐1个下载别人csdn文章笔记的java项目&#xff1a;csdn-blog2markword-downloader 拿到别人的md笔记后&#xff0c;但是笔记中的图片又是以链接的格式给的&#xff0c;这个链接说不定后面就失效了&#xff0c;笔记也就看不到图片了。手动右键也可以保存图片&#xff0c;但是…

前端学习笔记 7:小兔鲜

前端学习笔记 7&#xff1a;小兔鲜 准备工作 创建项目 创建项目&#xff1a; npm init vuelatest相关选项如下&#xff1a; 在src目录下添加以下目录&#xff1a; 别名路径联想 默认情况下在 VSCode 中输入import xxx from ...时不会启用路径联想功能&#xff0c;要启用需…

使用宝塔面板安装wiki.js详细教程

因为在安装过程中遇到了一些问题&#xff0c;花费了很长时间在解决问题上。根据这篇教程可以少踩很多坑。点赞加关注吧。 准备运行环境 Nodejs 在宝塔面板的软件商店中找到nodejs版本管理器并安装。 点击设置&#xff0c;选择一个稳定版安装。 PostgreSQL 官方推荐的数据库是…

用户洞察:精准解读用户的真实需求!

洞察用户需求的过程和谈恋爱一样。你不能简简单单地问客户&#xff0c;你想要什么&#xff1f;你有什么痛点&#xff1f;这样的问法是无法得到任何有价值的信息。这就好比谈恋爱的场景&#xff0c;如果你问对方想吃什么&#xff0c;大概率会得到“随便”“都行”这类的答案&…