正则表达式的基本理解与操作

本文深入解析正则表达式的特性与应用,涵盖基础语法、高级功能及常见使用场景,如字符匹配、边界处理、限定词等,通过实例演示如何灵活运用正则表达式进行文本处理。

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

正则表达式

正则表达式的特点是:

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

由于正则表达式主要应用对象是文本,因此它在各种文本编辑器场合都有应用,小到著名编辑器EditPlus,大到Microsoft Word、Visual Studio等大型编辑器,都可以使用正则表达式来处理文本内容。本篇主要通过几个例子阐述本人对正则表达式的理解。

字符匹配「\d」

p("abc".matches("..."));
p("a8729a".replaceAll("\\d", "-"));
Pattern p = Pattern.compile("[a-z]{3}");
Matcher m = p.matcher("fgh");
p(m.matches());
p("fgha".matches("[a-z]{3}"));

public static void p(Object o) {
		System.out.println(o);
}
运行结果:
true
a----a
true
false
  1. 一个点表示一个字符,所以返回true。
  2. \d表示0~9数字,replaceAll则是将前置参数替换成后置参数。
  3. {n,m}表示字符所占有的个数为n~m个。

正则表达式的进一步了解

p("a".matches("."));
p("aa".matches("aa"));
p("aaaa".matches("a*"));
p("aaaa".matches("a+"));
p("".matches("a*"));
p("aaaa".matches("a?"));
p("".matches("a?"));
p("a".matches("a?"));
p("214523145234532".matches("\\d{3,100}"));
p("192.168.0.aaa".matches("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"));
p("192".matches("[0-2][0-9][0-9]"));
运行结果:
true
true
true
true
true
false
true
true
true
false
true
  1. X*表示出现零次或者多次
  2. X+表示出现一次或者多次
  3. X?表示出现零个或者一次
  4. \d{1,3}表示数字出现1~3次
  5. 用[ ]限制字符的范围,如[a,b,c]或者[1~6]等。

正则化限制范围

p("a".matches("[abc]"));
p("a".matches("[^abc]"));
p("A".matches("[a-zA-Z]"));
p("A".matches("[a-z]|[A-Z]"));
p("A".matches("[a-z[A-Z]]"));
p("R".matches("[A-Z&&[RFG]]"));
运行结果:
true
false
true
true
true
true
  1. ^X表示取「除了X外的值」
  2. &&表示并且,就是求其交集。

「\s \w \」 的使用

p(" \n\r\t".matches("\\s{4}"));
p(" ".matches("\\S"));
p("a_8".matches("\\w{3}"));
p("abc888&^%".matches("[a-z]{1,3}\\d+[&^#%]+"));
p("\\".matches("\\\\"));
运行结果:
true
false
true
true
true
  1. \ s表示一个空白字符,如空格,tab键,换行等,\ S表示非空白字符。
  2. \ w表示大小写字母、数字以及 ‘_’ 下划线,\ W则是匹配除了他们之外的字符。
  3. 在匹配反斜杠「\」的时候,需要在加一条反斜杠转意。

POSIX Style 「\p」

p("a".matches("\\p{Lower}"));
p("S".matches("\\p{Upper}"));
运行结果:
true
true

\p{Lower}和\p{Upper}表示匹配所有小写或者大写的字母。

正则表达式边界处理 「\b」

p("hello sir".matches("^h.*"));
p("hello sir".matches(".*ir$"));
p("hello sir".matches("^h[a-z]{1,3}o\\b.*"));
p("hellosir".matches("^h[a-z]{1,3}o\\b.*"));
//统计空白行,开头为空白字符且不为换行符,结尾为换行符。
p(" \n".matches("^[\\s&&[^\\n]]*\\n$"));
		
p("aaa 8888c".matches(".*\\d{4}."));
p("aaa 8888c".matches(".*\\b\\d{4}."));
p("aaa8888c".matches(".*\\d{4}."));
p("aaa8888c".matches(".*\\b\\d{4}."));
运行结果
true
true
true
false
true

true
true
true
false
  1. 当 ^ 在[ ]外时,^X表示以X开头。
  2. 相对应,X$表示以X作为结尾。
  3. \ b表示单词的边界,空格,回车等都能作为单词的边界。

匹配email格式字符串

p("asdfasdfsafsf@dsdfsdf.com".matches("[\\w[.-]]+@[\\w[.-]]+\\.[\\w]+"));
运行结果:
true

[ .- ]是为了预防个别email格式。

「find」和「 lookingAt」

Pattern p = Pattern.compile("\\d{3,5}");
String s = "123-34345-234-00";
Matcher m = p.matcher(s);
p(m.matches());
m.reset();
p(m.find());
p(m.start() + "-" + m.end());
p(m.find());
p(m.start() + "-" + m.end());
p(m.find());
p(m.start() + "-" + m.end());
p(m.find());
//p(m.start() + "-" + m.end());
p(m.lookingAt());
p(m.lookingAt());
p(m.lookingAt());
p(m.lookingAt());
运行结果:
false
true
0-3
true
4-9
true
10-13
false
true
true
true
true
  1. find表示匹配第一个符合要求的字符,不过需要注意的是,果然继续使用find的话,下次的字符串就不包括之前已经匹配出的内容。
  2. start和end表示匹配出的字符串开始和结束的位置,如果匹配失败是不能使用这两种方法的。
  3. lookingAt表示从开始位置开始匹配,不管调用几次都是从开头位置开始匹配,相对于find从某种方面来看就是相反的。

appendReplacement

Pattern p = Pattern.compile("java", Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher("java Java JAVa JaVa IloveJAVA you hateJava afasdfasdf");
StringBuffer buf = new StringBuffer();
int i=0;
while(m.find()) {
	i++;
	if(i%2 == 0) {
		m.appendReplacement(buf, "java");
	} else {
		m.appendReplacement(buf, "JAVA");
	}
}
m.appendTail(buf);
p(buf);
运行结果:
JAVA java JAVA java IloveJAVA you hatejava afasdfasdf
  1. 可见字符串中,java各式各样,有大写有小写的,为了都匹配出来,这里引用了Pattern.CASE_INSENSITIVE,即匹配出所有的java而且无视其大小写。
  2. appendReplacement表示将匹配到得字符串替换成后置参数,并添加到前置参数去。
  3. appendTail的目的是将尾部没有匹配的字符串添加至buf字符串中。

「group」

Pattern p = Pattern.compile("(\\d{3,5})([a-z]{2})");
String s = "123aa-34345bb-234cc-00";
Matcher m = p.matcher(s);
while(m.find()) {
	p(m.group());
	p(m.group(1));
	p(m.group(2));
	p("-----------");
}
运行结果:
123aa
123
aa
-----------
34345bb
34345
bb
-----------
234cc
234
cc
-----------

group是返回匹配到的字符串。不过我们可以通过将匹配规则进行分组处理,在使用group返回的时候,可以选择返回指定的组别。

qulifiers 限定词

Pattern p = Pattern.compile("(.{3,10}?)[0-9]");
Pattern p1 = Pattern.compile("(.{3,10}+)[0-9]");
String s = "aaaa5bbbb68";
Matcher m = p.matcher(s);
Matcher m1 = p1.matcher(s);
if(m.find())
	p(m.start() + "-" + m.end());
else 
	p("not match!");
if(m1.find())
	p(m1.start() + "-" + m1.end());
else 
	p("not match!");
运行结果:
0-5
0-11

qulifiers中,在匹配一组字符后面加?和+的区别在于,?是将匹配规则的最小字符数量载入,判断是否满足匹配规则,而+则是将匹配规则的最大字符数量载入,判断是否满足条件。

non-capturing groups 非捕获组

Pattern p = Pattern.compile(".{3}(?=a)");
String s = "444a66b";
Matcher m = p.matcher(s);
while(m.find()) {
	p(m.group());
}
运行结果:
444

其中(?= X)放在匹配规则后面时,表示以X结尾,且不包含在返回结果中;当放在匹配规则前面时,表示以X为开头,且包含在返回结果中。还有一种写法是(?! X)表示不以X开头或者不以X结尾。

back refenrences 向前引用

Pattern p = Pattern.compile("(\\d\\d)\\1");
String s = "1212";
Matcher m = p.matcher(s);
p(m.matches());
运行结果:
true

其中\1表示与第一组匹配的结果必须相同,在例子中,第一组的匹配规则为(\d\d),则匹配的结果为12,则\1表示匹配的字符之后跟的必须也是12,所以是匹配成功的,如果匹配字符是1234则匹配失败。

flags的简写

Pattern p = Pattern.compile("java", Pattern.CASE_INSENSITIVE);
p("Java".matches("(?i)(java)"));
运行结果:
true

例子中的两种匹配规则效果相同,下面的为上面规则的简写,这里的(?!)就等价于了Pattern.CASE_INSENSITIVE。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值