java正则表达式
1、正则表达式的作用
正则表达式定义了字符串的模式
正则表达式可以用来搜索、编辑和处理文本
2、正则表达式的匹配规则
字符 | 描述 |
---|---|
\A | 匹配字符串开头 |
\b | 匹配一个字边界,即字与空格的位置,如“er\b”匹配“never”中的“er”,但不匹配“verb”中的“er” |
\B | 匹配非字边界,如“er\b”匹配“verb”中的“er”,但不匹配“never”中的“er” |
\d | 匹配数字字符,等效于[0-9] |
\D | 匹配非数字字符,等效于[ ^ 0 - 9 ] |
\f | 匹配换页符 |
\G | 匹配最后匹配完成的位置 |
\n | 匹配换行符 |
\r | 匹配一个回车符 |
\s | 匹配任何空白字符,包括空格、制表符、换页符、换行符等 |
\S | 匹配任何非空白字符 |
\t | 匹配制表符 |
\v | 匹配垂直制表符 |
\w | 匹配字母、数字、下划线 |
\W | 匹配非字母、数字、下划线 |
\z | 匹配字符串结尾,若存在换行,则只匹配到换行前的结束字符 |
\Z | 匹配字符串结尾,若存在换行,同时还会匹配换行符 |
^ | 匹配输入字符串的开始位置 |
$ | 匹配输入字符串的结尾位置 |
x|y | 匹配x或y |
[xyz] | 字符集,匹配中括号中包含的任意一字符 |
[^xyz] | 反向字符集,匹配中括号中未包含的任意字符 |
[a-z] | 字符范围,匹配指定范围内的任何字符,如[a-z]匹配a到z范围内的任意字符 |
[^a-z] | 反向字符范围,匹配不在指定范围内的任何字符,如[ ^a-z ]匹配不在a到z范围内的任意字符 |
* | 匹配0个或多个前面的字符或表达式,如zo*与z和zo、zoo匹配,等价于{0,} |
+ | 匹配1个或多个前面的字符或表达式,如zo+与zo和zoo匹配,但无法和z匹配 |
? | 匹配0个或1个前面的字符或表达式,如do(es)?与do或does匹配 |
{n} | n是非负整数,匹配n次,如o{2}与Bob不匹配,但与food匹配 |
{n,} | n是非负整数,至少匹配n次,如o{2,}与Bob不匹配,但与food、fooood匹配 |
{n,m} | m,n是非负整数,且n<=m,至少匹配n次,至多匹配m次,如o{1,3}只能匹配foooooood中的前3个o |
3、实例
1.手机号码:
手机号码长11位,且总是以数组1开始的,我们直接写1就好,后面还有10位可以是0-9范围内的任意数字,那么我们可以用\d或[0-9]来表示,要匹配10次,我们可以在后面加上{10},因此最后的匹配串可以是^1\d{10}$或者^1[0-9]{10}$
2.IPV4地址:
IPV4 地址的格式是a.b.c.d,其中a,b,c,d是[0,255]上的任意数,a,b,c,d的考虑方式是一样的,因此我们拿出一个a来举例,[0,255]间的数可以是一位、两位或三位,如果是一位那么它可以是[0-9],如果是两位,那么可以是[1-9][0-9],如果是三位,可以是1[0-9]{2}|2[0-4][0-9]|25[0-5],那么合并起来就是[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5],数字之后是点“.”,我们需要用转义符写成\.,由于数字是个整体,所有我们用括号括起来,那么一个数字和一个点就表达成([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.,我们将这段字符重复三次后再加上一个[0-255]的数字即可,因此IPV4地址最终表示成(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])
4、java中的正则表达式
java中的正则表达式来自于java.util.regex包,该包中主要包括Pattern、Matcher、PatternSyntaxException三个类
Pattern类:
用于表达和陈述所要搜索模式的对象,可以创建一个匹配模式,从源码中可以看到Pattern的构造函数时私有的,我们无法直接创建一个Pattern实例,
//Pattern构造函数源码
private Pattern(String p, int f) {
pattern = p;
flags = f; // to use UNICODE_CASE if UNICODE_CHARACTER_CLASS present
if ((flags & UNICODE_CHARACTER_CLASS) != 0)
flags |= UNICODE_CASE; // Reset group index count
capturingGroupCount = 1;
localCount = 0;
if (pattern.length() > 0) {
compile();
} else {
root = new Start(lastAccept);
matchRoot = lastAccept;
}
}
但我们可以用Pattern.compile(String regex)方法创建一个正则表达式,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);
}
创建方式:
Pattern p = Pattern.compile("\\d+");
p.pattern();//返回正则表达式的字符串形式,即compile中的参数regex
Pattern.matches(CharSequence input)方法是一个类方法,可以用于检测字符串是否匹配给定的正则表达式,可以从源码中可以看到该函数最终还是通过调用Matcher的对象方法完成判断的
public static boolean matches(String regex, CharSequence input) {
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(input);
return m.matches();
}
然而这个方法是全局匹配的,即会匹配整个字符串,相当于传入的正则表达式为regex,但实际他做的事情是匹配^regex$,因此下面的三个匹配结果分别为true,false,false
System.out.println(Pattern.matches("\\d+","12"));
System.out.println(Pattern.matches("\\d+","12aa"));
System.out.println(Pattern.matches("\\d+","12aa12"));
pattern.matcher方法会返回一个Matcher实例,由于Matcher的构造器是包外不可见的,所以通常我们也只能通过pattern.matcher来获取Matcher的实例对象
public Matcher matcher(CharSequence input) {
if (!compiled) {
synchronized(this) {
if (!compiled)
compile();
}
}
Matcher m = new Matcher(this, input);
return m;
}
Matcher类:
Matcher是一个匹配器类,是解释Pattern对Character sequence执行匹配操作的引擎,Matcher是一个Final类,因此无法被继承,且构造器是默认权限的,无法被包外的对象访问
Matcher(Pattern parent, CharSequence text) {
this.parentPattern = parent;
this.text = text;
// Allocate state storage
int parentGroupCount = Math.max(parent.capturingGroupCount, 10);
groups = new int[parentGroupCount * 2];
locals = new int[parent.localCount];
// Put fields into initial states
reset();
}
Matcher.matches()方法在上面提到了,他会对字符串进行全局匹配,只有整个字符串都匹配了才会返回true
Matcher.lookingAt()方法会对前面的字符串进行匹配,只有当匹配到的字符串在母串最前面才会返回true,例如以下代码输出的结果为true,false
Pattern p1 = Pattern.compile("\\d+a");
Pattern p2 = Pattern.compile("a\\d+");
Matcher m = p1.matcher("12aa12");
System.out.println(m.lookingAt());
m = p2.matcher("12aa12");
System.out.println(m.lookingAt());
Matcher.find()方法的要求则比较宽松,可以匹配到输入的字符串的任意子串,例如以下三种情况输出都为true:
Pattern p1 = Pattern.compile("\\d+a");
Pattern p2 = Pattern.compile("a\\d+");
Pattern p3 = Pattern.compile("\\d+");
Matcher m = p1.matcher("12aa12");
System.out.println(m.find());
m = p2.matcher("12aa12");
System.out.println(m.find());
m = p3.matcher("12aa12");
System.out.println(m.find());
Matcher.start()方法返回匹配到的子串第一个字符在母串中的索引位置
Matcher.end()方法返回匹配到的子串最后一个字符在母串中的索引位置
Matcher.group()方法返回匹配到的字符串
5、实例:
以上面的IPV4地址为例:
public class MyRegex {
public static void main(String[] args) {
Pattern p = Pattern.compile("(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])");
String url = "address:127.0.0.1(IPV4)";
Matcher m = p.matcher(url);
System.out.println("匹配结果:"+m.find());
System.out.println("匹配到的字符串的开始位置:"+m.start());
System.out.println("匹配到的字符串的结束位置:"+m.end());
System.out.println("匹配到的字符串:"+m.group());
}
}
运行结果:
匹配结果:true
匹配到的字符串的开始位置:8
匹配到的字符串的结束位置:17
匹配到的字符串:127.0.0.1