正则表达式基础语法与Java、JS使用实例

【1】转义字符

一些不便书写的字符,采用在前面加 "\" 的方法。

字符描述
\cx匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 ‘c’ 字符。
\f匹配一个换页符。等价于 \x0c 和 \cL。
\n匹配一个换行符。等价于 \x0a 和 \cJ。
\r匹配一个回车符。等价于 \x0d 和 \cM。
\s匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。注意 Unicode 正则表达式会匹配全角空格符。
\S匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\t匹配一个制表符。等价于 \x09 和 \cI。
\v匹配一个垂直制表符。等价于 \x0b 和 \cK。

还有其他一些在后边章节中有特殊用处的标点符号,在前面加"\" 后,就代表该符号本身。

比如:^, $ 都有特殊意义,如果要想匹配字符串中 "^" 和 "$" 字符,则表达式就需要写成 "\^" 和 "\$"


【2】与 ‘多种字符’ 匹配

字符描述
.(小数点)除了换行符(\n)以外的任何一个字符;
\d任意一个数字,0~9 中的任意一个;
\D匹配所有的非数字字符;
\w任意一个字母或数字或下划线,也就是A~Z,a~z,0~9,_ 中任意一个;
\W匹配所有的字母、数字、下划线以外的字符;
\s包括空格、制表符、换页符等空白字符的其中任意一个;
\S匹配所有非空白字符(“/s” 可匹配各个空白字符);
\b匹配一个单词边界,也就是单词和空格之间的位置,不匹配任何字符;
\B匹配非单词边界,即左右两边都是 “/w” 范围或者左右两边都不是 “/w” 范围时的字符缝隙;
\xXX编号在 0 ~ 255 范围的字符,比如:空格可以使用"/x20" 表示;
\uXXXX任何字符可以使用 “/u” 再加上其编号的4 位十六进制数表示,比如:“/u4E2D”。

当然 你也可以自定义能够匹配 ‘多种字符’ 的表达式

[ab5@]    匹配 "a" 或 "b" 或 "5" 或 "@"
[^abc]    匹配 "a","b","c" 之外的任意一个字符
[f-k]     匹配 "f"~"k" 之间的任意一个字母
[^A-F0-3] 匹配 "A"~"F","0"~"3" 之外的任意一个字符

【3】特殊元字符

所谓特殊字符,就是一些有特殊含义的字符。许多元字符要求在试图匹配它们时特别对待。若要匹配这些特殊字符,必须首先使字符"转义",即,将反斜杠字符\ 放在它们前面。

① 正则表达式中的特殊字符

字符描述
$匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 '\n' 或 '\r'。要匹配 $ 字符本身,请使用 \$
( )标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 \( 和 \)
*匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 \*
+匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 \+
.匹配除换行符 \n 之外的任何单字符。要匹配 . ,请使用 \. 。注意[.].表示自身不用转义
[标记一个中括号表达式的开始。要匹配 [,请使用 \[
?匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 \?
\将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, 'n' 匹配字符 'n'。'\n' 匹配换行符。序列 '\\' 匹配 "\",而 '\(' 则匹配 "("
^匹配输入字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符后面字符集合。要匹配 ^ 字符本身,请使用 \^
{标记限定符表达式的开始。要匹配 {,请使用 \{
``
(pattern)匹配 pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中则使用 $0…$9 属性。要匹配圆括号字符,请使用 '\(' 或 '\)'。
(?:pattern)匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 `“或” 字符 (
(?=pattern)正向肯定预查(look ahead positive assert)。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
(?!pattern)正向否定预查(negative assert)。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
(?<=pattern)反向(look behind)肯定预查,与正向肯定预查类似,只是方向相反。
(?<!pattern)反向否定预查,与正向否定预查类似,只是方向相反。

② ()— (?:pattern)

这两个是相互对应的,前者表示捕获匹配的分组,后者表示不捕获匹配的分组。?: 与?= ?! ?<= ?<!没有对应/区别关系。

③ (?=pattern) (?!pattern) (?<=pattern) (?<!pattern)

=与!表示是与否,?=与?<=前者是正向预查,后者是反向预查。

什么是正向(前瞻)与反向(后顾)?

正则表达式中有前瞻(Lookahead)和后顾(Lookbehind)的概念,这两个术语非常形象的描述了正则引擎的匹配行为。需要注意一点,正则表达式中的前和后和我们一般理解的前后有点不同。一段文本,我们一般习惯把文本开头的方向称作“前面”,文本末尾方向称为“后面”。但是对于正则表达式引擎来说,因为它是从文本头部向尾部开始解析的(可以通过正则选项控制解析方向),因此对于文本尾部方向,称为“前”,因为这个时候,正则引擎还没走到那块,而对文本头部方向,则称为“后”,因为正则引擎已经走过了那一块地方。

在这里插入图片描述
所谓的前瞻就是在正则表达式匹配到某个字符(如上图蓝色区域)的时候,往“尚未解析过的文本”预先看一下,看是不是符合/不符合匹配模式。而后顾,就是在正则引擎已经匹配过的文本看看是不是符合/不符合匹配模式。符合和不符合特定匹配模式我们又称为肯定式匹配否定式匹配

字符串缝隙与两头

"^","$","\b",它们都有一个共同点,那就是:它们本身不匹配任何字符,只是对 “字符串的两头” 或者 “字符之间的缝隙” 附加了一个条件。
"(?=xxxxx)",在被匹配的字符串中,它对所处的 “缝隙” 或者 “两头” 附加的条件是:所在缝隙的右侧,必须能够匹配上 xxxxx 这部分的表达式。因为它只是在此作为这个缝隙上附加的条件,所以它并不影响后边的表达式去真正匹配这个缝隙之后的字符。这就类似 "\b",本身不匹配任何字符。"\b" 只是将所在缝隙之前、之后的字符取来进行了一下判断,不会影响后边的表达式来真正的匹配。

实例如下:

 String str="1122009-07-08 04:38:44";
 
 //字符串112后面是2009-07-08,不匹配
 String regex = "^112(?<=2009-07-08).*$";//false

//字符串112前面是2009-07-08,匹配
String regex = "^112(?=2009-07-08).*$";//true

//字符串112后面不是2009-07-08,匹配
String regex = "^112(?<!2009-07-08).*$";//true

//字符串112前面不是2009-07-08,不匹配
String regex = "^112(?!2009-07-08).*$";//false
boolean matches = Pattern.matches(regex, str);
System.out.println(matches);

上面例子中表达式后面都是使用.*来匹配任意字符,那么为了更好理解“(?=pattermn)只是作为缝隙的附件条件,不参与真正字符串匹配”,下面看另外一个实例:

 String str="1A123dasf";
 
//1右侧必须跟着123,显然不匹配
String regex = "^1(?=123).*$";//false

//1右侧必须跟着A,后面的表达式与1组合起来和str进行匹配
String regex = "^1(?=A).*$";//true
String regex = "^1(?=A)A1.*$";//true
String regex = "^1(?=A)A123.*$";//true
String regex = "^1(?=A)A123dasf.*$";//true
String regex = "^1(?=A)A123dasf$";//true

//str中1后面虽然跟着A,但是正则校验是1abc,与str不匹配
String regex = "^1(?=A)abc$";//false

//正则校验表达式1A123dasf与str匹配,但是缝隙处后面必须跟着B,故而仍旧为false
String regex = "^1(?=B)A123dasf$";//false
boolean matches = Pattern.matches(regex, str);
System.out.println(matches);

另外XXXX部分除了可以是字符串外还可以是标准正则

实例如下:

 @Test
public void testRegexFile(){
      String name="123456";
	//1前面不能是2
      Pattern pattern = Pattern.compile("^1(?!2)23456$"); //false

	//1前面不能是字母数字下划线
      Pattern pattern = Pattern.compile("^1(?!\\w)23456$"); //false

	//1前面不能是除了字母数字下划线的--1前面必须是字母数字下划线
      Pattern pattern = Pattern.compile("^1(?!\\W)23456$");//true

     //1前面必须是235
      Pattern pattern = Pattern.compile("^1(?=235)23456$");//false

      //1前面必须是23
      Pattern pattern = Pattern.compile("^1(?=23)23456$");//true

	//必须是一个(字母数字下划线)23开头的
      Pattern pattern = Pattern.compile("^(?=\\w+?23)123456$");//true
      boolean matches = pattern.matcher(name).matches();
      System.out.println(matches);
}

【4】修饰匹配次数的特殊符号-限定符

限定符用来指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。有 * 或 + 或 ? 或 {n} 或 {n,} 或 {n,m} 共6种。

字符描述
*匹配前面的子表达式零次或多次。例如,zo* 能匹配 “z” 以及 “zoo”。* 等价于{0,}。
+匹配前面的子表达式一次或多次。例如,‘zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等价于 {1,}。
?匹配前面的子表达式零次或一次。例如,“do(es)?” 可以匹配 “do” 、 “does” 中的 “does” 、 “doxy” 中的 “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?’。请注意在逗号和两个数之间不能有空格。

【5】贪婪与非贪婪

*、+限定符都是贪婪的,因为它们会尽可能多的匹配文字,只有在它们的后面加上一个?就可以实现非贪婪或最小匹配。

例如,您可能搜索 HTML 文档,以查找括在 H1 标记内的章节标题。该文本在您的文档中如下:

<H1>Chapter 1 - 介绍正则表达式</H1>

贪婪:下面的表达式匹配从开始小于符号 (<) 到关闭 H1 标记的大于符号 (>) 之间的所有内容。

<.*>

非贪婪:如果您只需要匹配开始和结束 H1 标签,下面的非贪婪表达式只匹配 <H1></H1>。

<.*?>

这里也可以标明非贪婪的含义,并不是说只是匹配单个字符,而是相对原来实现最小匹配!仔细体会上面两个例子。

如果只想匹配开始的 H1 标签,表达式则是:

<\w+?>

通过在 *、+ 或 ? 限定符之后放置 ?,该表达式从"贪心"表达式转换为"非贪心"表达式或者最小匹配。即*? +? ??


【6】选择子表达式()

圆括号()是组,主要应用在限制多选结构的范围/分组/捕获文本/环视/特殊模式处理。()内的内容表示的是一个子表达式,()本身不匹配任何东西,也不限制匹配任何东西,只是把括号内的内容作为同一个表达式来处理,例如(ab){1,3},就表示ab一起连续出现最少1次,最多3次。

用圆括号将所有选择项括起来,相邻的选择项之间用|分隔。但用圆括号会有一个副作用,使相关的匹配会被缓存,此时可用?:放在第一个选项前来消除这种副作用。

其中 ?: 是非捕获元之一,还有两个非捕获元是 ?= 和 ?!,这两个还有更多的含义,前者为正向预查,在任何开始匹配圆括号内的正则表达式模式的位置来匹配搜索字符串,后者为负向预查,在任何开始不匹配该正则表达式模式的位置来匹配搜索字符串。

示例:

1、(abc|bcd|cde),表示这一段是abc、bcd、cde三者之一均可,顺序也必须一致
2、(abc)?,表示这一组要么一起出现,要么不出现,出现则按此组内的顺序出现
3、(?:abc)表示找到这样abc这样一组,但不记录,不保存到$变量中,否则可以通过$x取第几个括号所匹配到的项,
比如:(aaa)(bbb)(ccc)(?:ddd)(eee),可以用$1获取(aaa)匹配到的内容,而$3则获取到了(ccc)匹配到的内容,
而$4则获取的是由(eee)匹配到的内容,因为前一对括号没有保存变量。

4、a(?=bbb) 顺序环视 表示a后面必须紧跟3个连续的b
5、(?i:xxxx) 不区分大小写 (?s:.*) 跨行匹配.可以匹配回车符

【7】反向引用

对一个正则表达式模式或部分模式两边添加圆括号将导致相关匹配存储到一个临时缓冲区中,所捕获的每个子匹配都按照在正则表达式模式中从左到右出现的顺序存储。缓冲区编号从 1 开始,最多可存储 99 个捕获的子表达式。每个缓冲区都可以使用\n访问,其中 n 为一个标识特定缓冲区的一位或两位十进制数。

可以使用非捕获元字符 ?:、?= 或 ?! 来重写捕获,忽略对相关匹配的保存。

反向引用的最简单的、最有用的应用之一,是提供查找文本中两个相同的相邻单词的匹配项的能力。以下面的句子为例:

Is is the cost of of gasoline going up up?

上面的句子很显然有多个重复的单词。如果能设计一种方法定位该句子,而不必查找每个单词的重复出现,那该有多好。下面的正则表达式使用单个子表达式来实现这一点:

var str = "Is is the cost of of gasoline going up up";
var patt1 = /\b([a-z]+) \1\b/ig;
document.write(str.match(patt1));

获的表达式,正如 [a-z]+ 指定的,包括一个或多个字母。正则表达式的第二部分是对以前捕获的子匹配项的引用,即,单词的第二个匹配项正好由括号表达式匹配。\1 指定第一个子匹配项。

单词边界元字符确保只检测整个单词。否则,诸如 “is issued” 或 “this is” 之类的词组将不能正确地被此表达式识别。

正则表达式后面的全局标记 g 指定将该表达式应用到输入字符串中能够查找到的尽可能多的匹配。

表达式的结尾处的不区分大小写 i 标记指定不区分大小写。

多行标记指定换行符的两边可能出现潜在的匹配。


【8】Java正则校验

① 要求:字母、数字和特殊符号中的二者或二者以上。

@Test
public void testReg(){
	String reg="^[0-9]+\\D+.*|\\D+\\d+.*$";
	String value = "#@@#$123";
	boolean matches = Pattern.matches(reg, value);
	System.out.println("是否匹配 :"+matches);
}

核心语法 Pattern.matches(reg, value);使用起来十分简洁。

查看其源码如下:

 public static boolean matches(String regex, CharSequence input) {
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(input);
        return m.matches();
    }

② Pattern

Pattern是正则表达式的编译表示,字符串格式的正则表达式必须首先编译为该类的实例。然后使用编译后得到的Pattern实例创建一个Matcher对象来匹配任意的字符序列。

也就是说通常有四步:

  • 编写字符串格式正则;
  • 根据正则表达式获取Pattern实例;
  • 根据Pattern实例和待校验的字符序列获取Matcher实例;
  • 使用Matcher.matches()方法获取校验结果

修改上面方法如下所示:

@Test
public void testReg2() {
	//① 
	String reg="^[0-9]+\\D+.*|\\D+\\d+.*$";
	// ② 
	Pattern pattern = Pattern.compile(reg);
	//③ 
	String string = "#@@#$123";
	Matcher matcher = pattern.matcher(string);
	//④ 
	boolean b = matcher.matches();
	System.out.println("是否匹配 :"+b);
}

③ ()的应用

实例一:

@Test
public void contextLoads() {
	String regex = "([a-z])([A-Z])";
	String replacement = "$1_$2";
	String origin = "iD";
	String newName = origin.replaceAll(regex, replacement);
	System.out.println("newName : "+newName);
}

result:

newName : i_D

注意,这里实例中regex 并非以^开头,以$结尾

实例二:

@Test
public void contextLoads() {
	String regex = "^([a-z])*([A-Z])*\\w$";
	String replacement = "$1_$2";
	String origin = "addressId";
	boolean b = Pattern.matches(regex, origin);
	System.out.println("match result : "+b);
	String newName = origin.replaceAll(regex, replacement);
	System.out.println("newName : "+newName);
}

result:

match result : true
newName : s_I

【9】JS中正则使用

① 两种创建正则表达式(对象)方法

#字面量方式创建
var  reg = /^aabb$/g; //g可省

#实例方式创建
var  regexp = new RegExp("xyz","g"); //第二个参数可省 等于/xyz/g

两个实例如下:
var regNum = /^\d{11}$/;
var re = new RegExp(regNum);
var phone = $("#phone").val();
console.log("phone : "+phone);
if(!re.test(phone)){
	alert("请输入11位手机号!");
	return false;
}
var regAge = /^[1-9]{1}\d{1,2}$/;
var age = $("#age").val();
if(!regAge.test(age)){
	alert("请输入正确年龄!");
	return false;
}

正则对象的方法是指这样使用的: RegExp对象.方法(字符串)

如校验上传文件格式为图片:

var reg=/^image///\w+$/g;
if(reg.test(file.type)){
	console.log("上传的是图片格式")
}

② 正则对象的属性

属性如下:

ignoreCase //返回一个布尔值表示正则对象是否设置了i修饰符,是一个只读属性

global //表示正则对象是否设置了g修饰符,返回布尔值

multiline //表示是否设置了m修饰符,返回一个布尔值

lastIndex //返回下一次开始搜索的位置,该属性可读写,但只在设置了g修饰符时有意义

source //返回正则表达式的字符串形式(不包括反斜杠),只读属性

在这里插入图片描述

  • i --执行忽略大小写的匹配

  • g --执行全局匹配(可以查看所有的匹配而不是只找到第一个匹配后就停止)

  • m --执行多行匹配


③ test方法

test方法返回布尔值,用来验证字符串是否符合某个模式。

如果正则表达式带有g修饰符,则每一次test方法都从上一次匹配结束的位置开始匹配。

使用了g修饰符的正则对象,表示要记录搜索的位置,接着使用test方法,每次开始搜索的委会都是上一次匹配的后一个位置:

在这里插入图片描述

如果正则表达式是一个空字符串,则会匹配所有的字符串,但前提是使用new RegExp()的方式:
在这里插入图片描述


④ exec方法

exec()返回匹配的结果,匹配成功exec方法返回装有匹配结果的数组,匹配失败返回null:
在这里插入图片描述

如果正则表达式包含圆括号,则返回的数组会包括多个元素。首先是整个匹配成功的结果,后面是圆括号里匹配成功的结果,如果有多个圆括号,他们的匹配成功的结果都会成为数组元素:
在这里插入图片描述

对于调用exec方法后返回的数组具有以下两个属性:

input --整个原待匹配的字符串

index --整个模式匹配成功的开始位置

同样,给正则表达式加上g修饰符就可以多次使用exec方法,下一次搜索的位置从上一次成功匹配结束的位置开始。


⑤ 字符串 match()方法

实例如下:

var str = "http://www.runoob.com:80/html/html-tutorial.html";
var patt1 = /(\w+):\/\/([^/:]+)(:\d*)?([^# ]*)/;
arr = str.match(patt1);
console.log(arr);
for (var i = 0; i < arr.length ; i++) {
    document.write(arr[i]);
	document.write("<br>");
}

在这里插入图片描述

字符串.match()方法等效于RegExp.exec()方法。


第三行代码 str.match(patt1) 返回一个数组,实例中的数组包含 5 个元素,索引 0 对应的是整个字符串,索引 1 对应第一个匹配符(括号内),以此类推。

第一个括号子表达式捕获 Web 地址的协议部分。该子表达式匹配在冒号和两个正斜杠前面的任何单词。

第二个括号子表达式捕获地址的域地址部分。子表达式匹配 : 和 / 之后的一个或多个字符。

第三个括号子表达式捕获端口号(如果指定了的话)。该子表达式匹配冒号后面的零个或多个数字。只能重复一次该子表达式。

最后,第四个括号子表达式捕获 Web 地址指定的路径和 / 或页信息。该子表达式能匹配不包括 # 或空格字符的任何字符序列。

将正则表达式应用到上面的 URI,各子匹配项包含下面的内容:

第一个括号子表达式包含 http
第二个括号子表达式包含 www.runoob.com
第三个括号子表达式包含 :80
第四个括号子表达式包含 /html/html-tutorial.html

【10】正则表达式中运算符优先级

正则表达式从左到右进行计算,并遵循优先级顺序,这与算术表达式非常类似。

相同优先级的从左到右进行运算,不同优先级的运算先高后低。下表从最高到最低说明了各种正则表达式运算符的优先级顺序:

运算符描述
\转义符
(), (?:), (?=), []圆括号和方括号
*, +, ?, {n}, {n,}, {n,m}限定符
^, $, \任何元字符、任何字符定位点和序列(即:位置和顺序)
``

【11】Pattern与Matcher

① Pattern

① 静态方法compile

Pattern类有如下两个静态方法用来获取一个Pattern 对象。

public static Pattern compile(String regex) {
    return new Pattern(regex, 0);
}
public static Pattern compile(String regex, int flags) {
    return new Pattern(regex, flags);
}

flags为匹配模式,取值如下:

  • CASE_INSENSITIVE
  • MULTILINE
  • DOTALL
  • UNICODE_CASE
  • CANON_EQ
  • UNIX_LINES
  • LITERAL
  • UNICODE_CHARACTER_CLASS
  • COMMENTS

② 静态方法matches

进行全字符串匹配返回是否匹配上的boolean值。方法如下所示,其实是获取了Matcher 并调用了matcher的matches()方法。

public static boolean matches(String regex, CharSequence input) {
    Pattern p = Pattern.compile(regex);
    Matcher m = p.matcher(input);
    return m.matches();
}

② Matcher

Matcher类提供了对正则表达式的分组支持,以及对正则表达式的多次匹配支持,要想得到更丰富的正则匹配操作,那就需要将Pattern与Matcher联合使用。

一个Matcher对象实例如下所示,region表示目标字符串的区域范围,lastmatch表示上一个匹配的字符串。
在这里插入图片描述

① 检测是否匹配

boolean matches():尝试根据pattern匹配整个字符串。
lookingAt():尝试将输入序列与pattern相匹配,从区域(也就是输入字符串)的开头开始。
boolean find():尝试查找与模式匹配的输入序列的下一个子序列(任意位置哦)
boolean find(int start):重置此匹配器,然后尝试从指定索引开始查找与模式匹配的输入序列的下一个子序列。

这里要特别 注意find()方法,这个方法每调用一次,matcher的first 、last与oldLast都会发生改变哦
在这里插入图片描述
在这里插入图片描述
如下,获取字符串中的数字实例:

@Test
public void testMatchStr(){
    String source="共1天2";
    String regex="\\d+";
    Pattern compile = Pattern.compile(regex);
    Matcher matcher = compile.matcher(source);
    while(matcher.find()) {
            String group = matcher.group();
            System.out.println("**************************************************"+group);
    }
}

② 匹配的索引与内容

int start():返回上一个匹配项的开始索引。
int end():返回最后一个匹配字符后的偏移量。
String group():该方法其实调用了group(0),返回匹配的字符串内容。

③ 组

组是用括号()划分的正则表达式,可以根据组的编号来引用这个组。组号为0表示整个表达式,组号为1表示被第一对括号括起的组,依次类推。

例如A(B(C))D,group(0)=ABCD;group(1)=BD;group(2)=C

int start(int group) :返回给定组在上一次匹配操作中捕获的子序列的开始索引。
int end(int group):返回给定组在上一次匹配操作中捕获的子序列的最后一个字符后的偏移量。
String group(int group):返回给定组在上一次匹配操作中捕获的输入子序列。
String group(String name):返回在上一次匹配操作中由指定的捕获组捕获的输入子序列。

int groupCount():返回matcher's pattern中的捕获组数。

④ 内容追加

渐进式拼接字符串

Matcher appendReplacement(StringBuffer sb, String replacement)

拼接上次匹配后剩余内容。

public StringBuffer appendTail(StringBuffer sb) {
    sb.append(text, lastAppendPosition, getTextLength());
    return sb;
}

⑤ 字符串匹配替换实例

如下所示,将tempalte的占位符替换为param中实际的值。如${maxNumberofUEs}替换为10。

@Test
public void testRegexPattern(){
    String tempalte="2000*${maxNumberofUEs}*1*${purchaseNum}*1*(${expDataRateUL}*0.7+${expDataRateDL}*0.3)";
    JSONObject param=JSON.parseObject("{\"maxNumberofUEs\":\"10\",\"purchaseNum\":\"20\",\"expDataRateUL\":\"30\",\"expDataRateDL\":\"40\"}");
    String regex = "(\\$\\{(\\w+)\\})";
    Pattern p = Pattern.compile(regex);
    Matcher m = p.matcher(tempalte);
    StringBuffer content = new StringBuffer();
    while (m.find()) {
        String key = m.group(2);
        String value = "";
        if (param.containsKey(key)) {
            value = param.getString(key);
        } else {
           System.out.println("缺少参数 "+key);
        }
        if (StringUtils.isNotEmpty(value)) {
            Matcher matcher = m.appendReplacement(content, value);

        }
    }
    m.appendTail(content);
    System.out.println(content);
}

【12】常用正则实践总结

① 匹配汉字

String reg="^[\u4e00-\u9fa5]+$"

② 提取字符串中数字

// 根据正则表达式解析字符串中的目标对象
public static String parseNumFromStr(String source,String regex){
    Pattern compile = Pattern.compile(regex);
    Matcher matcher = compile.matcher(source);
    StringBuilder stringBuilder=new StringBuilder();
    while(matcher.find()) {
        String group = matcher.group();
        stringBuilder.append(group).append(",");
    }
    String string = stringBuilder.toString();
    return string.substring(0,string.length()-1);
}

// 解析字符串中的数字
public static String parseNumFromStr(String source){
    String regex="\\d+";
    Pattern compile = Pattern.compile(regex);
    Matcher matcher = compile.matcher(source);
    StringBuilder stringBuilder=new StringBuilder();
    while(matcher.find()) {
        String group = matcher.group();
        stringBuilder.append(group).append(",");
    }
    String string = stringBuilder.toString();
    return string.substring(0,string.length()-1);
}

③ 身份证号中间脱敏

如下所示可以使用正则匹配想要替换的部分,替换为*。下例保留前四后六,中间为*

String cardNo="400081202301114545";
String regex2="(?<=\\d{4}).*(?=\\d{6})";
String replaceAll = cardNo.replaceFirst(regex2, "********");

④ 根据正则进行字符串的部分替换

 /**
     * 根据正则进行字符串的部分替换,应用于脱敏场景
     * @param source 原字符串
     * @param replace 替换值
     * @param head 头个数
     * @param tail 尾个数
     * @return
     */
    public static String regexDesen(String source,String replace,int head,int tail){
        String regex="(?<=.{"+head+"}).(?=.{"+tail+"})";
        if(StringUtils.isEmpty(source)||replace==null){
            return source;
        }
        if(source.length()<=(head+tail)){
            return source;
        }
        return  source.replaceAll(regex,replace);
    }

    /**
     * 除后几位外,其余用*替代
     * @param source
     * @param replace
     * @param tail
     * @return
     */
    public static String regexDesenTail(String source,String replace,int tail){
        String regex=".(?=.{"+tail+"})";
        if(StringUtils.isEmpty(source)||replace==null){
            return source;
        }
        if(source.length()<=tail){
            return source;
        }
        return  source.replaceAll(regex,replace);
    }
    /**
     * 除前几位外,其余用*替代
     * @param source
     * @param replace
     * @param head
     * @return
     */
    public static String regexDesenHead(String source,String replace,int head){
        String regex="(?<=.{"+head+"}).";
        if(StringUtils.isEmpty(source)||replace==null){
            return source;
        }
        if(source.length()<=head){
            return source;
        }
        return  source.replaceAll(regex,replace);
    }

⑤ 密码由字母和数字组成且必须包含字母和数字

^(?=.*\d+)(?=.*[A-Za-z]+)[A-Za-z0-9]{6,20}$

(?=.*\d+) 表示任意字母后面需要跟着数字。

(?=.*[A-Za-z]+) 表示任意字母后面需要跟着字母。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流烟默

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值