正则表达式的正向预查和反向预查: ()、(?:)、(?=)、(?!)、(?<=)、(?<!)

本文深入探讨了正则表达式的高级应用,包括不同类型的预查、非获取匹配及如何在Java中正确使用这些特性避免常见错误。通过具体实例,如匹配手机号码并排除数字干扰,展示了正则表达式的强大功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

< 标记方向,这个符号说明是放在目标内容左边。

! 标记不匹配pattern,这符号说明目标内容的左边或右边,不能匹配pattern。

String s = "<Data ss:Type=\"String\">内容13</Data>";

 如下正则报错:* repetition not allowed inside lookbehind

s = s.replaceAll("(?<=<Data.+?>).+(?=</Data>)", "789");

原因:Java中正则表达式后行断言的限制,不能在后行模式中使用 * 或 + 限定符,允许有限制长度{1,1000},这里1000可以根据自己实际情况修改。

改成如下:

s = s.replaceAll("(?<=<Data.{1,1000}?>).+(?=</Data>)", "789");

运行结果:<Data ss:Type="String">789</Data>

(pattern)

匹配pattern并获取这一匹配。所获取的匹配可以从产生的Matches集合得到,在VBScript中使用SubMatches集合,在JScript中则使用$0…$9属性。要匹配圆括号字符,请使用“\(”或“\)”。

(?:pattern)

非获取匹配,匹配pattern但不获取匹配结果,不进行存储供以后使用。这在使用或字符“(|)”来组合一个模式的各个部分时很有用。例如“industr(?:y|ies)”就是一个比“industry|industries”更简略的表达式。

        String s = "123industry456industries789";
		Pattern p = Pattern.compile("industr(?:y|ies)");//(?:pattern)
		Matcher m = p.matcher(s);
		while (m.find()) {
			System.out.println(m.group());// 结果:industry、industries
		}
		p = Pattern.compile("industr(y|ies)");//(pattern)
		m = p.matcher(s);
		while (m.find()) {
			System.out.println(m.group());// 结果:industry、industries
		}

测试结果发现不要?:效果一样

(?=pattern)

非获取匹配,正向肯定预查(包含,后面),在任何匹配pattern的字符串开始处匹配查找字符串,该匹配不需要获取供以后使用。例如,“Windows(?=95|98|NT|2000)”能匹配“Windows2000”中的“Windows”,但不能匹配“Windows3.1”中的“Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。

(?!pattern)

非获取匹配,正向否定预查(不包含,后面),在任何不匹配pattern的字符串开始处匹配查找字符串,该匹配不需要获取供以后使用。例如“Windows(?!95|98|NT|2000)”能匹配“Windows3.1”中的“Windows”,但不能匹配“Windows2000”中的“Windows”。

(?<=pattern)

非获取匹配,反向肯定预查(包含,前面),与正向肯定预查类似,只是方向相反。例如,“(?<=95|98|NT|2000)Windows”能匹配“2000Windows”中的“Windows”,但不能匹配“3.1Windows”中的“Windows”。

(?<!pattern)

非获取匹配,反向否定预查(不包含,前面),与正向否定预查类似,只是方向相反。例如“(?<!95|98|NT|2000)Windows”能匹配“3.1Windows”中的“Windows”,但不能匹配“2000Windows”中的“Windows”。

示例:在一段文本中找出手机号,但是防止订单号干扰,即要求手机号前后不能有数字。

订单号:202109103154636545636 ,手机号码:18888888888。联系地址:xxx。

	public static void main(String[] args) {
		String s;
		Pattern p;
		Matcher m;
		// Pattern p = Pattern.compile("(?<!\\d)1\\d{10}(?!\\d)");//手机号1开头,总共11位,并且手机号前后都不能是数字。
		// 1、手机号必须是1开头,总共11位
		p = Pattern.compile("1\\d{10}");
		s = "18888888888";
		m = p.matcher(s);
		if (m.find()) {
			System.out.println(m.group());// 结果:18888888888
		}

		// 2、手机号必须是1开头,总共11位,并且手机号前面不能是数字
		p = Pattern.compile("(?<!\\d)1\\d{10}");
		s = "a18888888888";
		m = p.matcher(s);
		if (m.find()) {
			System.out.println(m.group());// 结果:18888888888
		}
		s = "918888888888";
		m = p.matcher(s);
		if (m.find()) {
			System.out.println(m.group());// 结果:空
		}

		// 3、手机号必须是1开头,总共11位,并且手机号后面不能是数字
		p = Pattern.compile("1\\d{10}(?!\\d)");
		s = "18888888888b";
		m = p.matcher(s);
		if (m.find()) {
			System.out.println(m.group());// 结果:18888888888
		}
		s = "188888888889";
		m = p.matcher(s);
		if (m.find()) {
			System.out.println(m.group());// 结果:空
		}

		// 4、手机号必须是1开头,总共11位,并且手机号前面和后面都不能是数字
		p = Pattern.compile("(?<!\\d)1\\d{10}(?!\\d)");
		s = "a18888888888b";
		m = p.matcher(s);
		if (m.find()) {
			System.out.println(m.group());// 结果:18888888888
		}
		s = "918888888888b";
		m = p.matcher(s);
		if (m.find()) {
			System.out.println(m.group());// 结果:空
		}
		s = "a188888888889";
		m = p.matcher(s);
		if (m.find()) {
			System.out.println(m.group());// 结果:空
		}
	}

1、不以XX开头

        String s = "AA12345";
		Pattern p = Pattern.compile("[^(AA)]\\w+");
		Matcher m = p.matcher(s);
		while (m.find()) {
			System.out.println(m.group());
		}

运行结果:12345

2、以XX开头:

		String s = "AA12345";
		Pattern p = Pattern.compile("(?<=AA)\\w+");
		Matcher m = p.matcher(s);
		while (m.find()) {
			System.out.println(m.group());
		}

运行结果:12345

3.不以XX结尾

        String s = "12345AA";
		Pattern p = Pattern.compile("\\w+[^(AA)]");
		Matcher m = p.matcher(s);
		while (m.find()) {
			System.out.println(m.group());
		}

运行结果:12345

4.以XX结尾

        String s = "12345AA";
		Pattern p = Pattern.compile("\\w+(?=AA)");
		Matcher m = p.matcher(s);
		while (m.find()) {
			System.out.println(m.group());
		}

运行结果:12345

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值