java夯实基础系列:正则表达式

来源:互联网 发布:阿里云邮箱官网下载 编辑:程序博客网 时间:2024/06/01 19:49

一.引入

需求:验证qq是否合法:5-15位,不能以0开头,全是数字

一般做法与使用正则表达式的做法:

public class Demo1 {    public static void main(String[] args) {        String qq = "a38703402948";        // 常规做法        boolean checkQQ = checkQQ(qq);        System.out.println(checkQQ);        // 使用正则表达式        String regex = "[1-9][0-9]{4,14}";        boolean b = qq.matches(regex);        System.out.println(b);    }    private static boolean checkQQ(String qq) {        int len = qq.length();        if (len < 5 || len > 15) {            System.out.println(qq + "号的长度不合法");            return false;        }        if (qq.startsWith("0")) {            System.out.println(qq + "号以0开头了");            return false;        }        try {            long num = Long.parseLong(qq);        } catch (NumberFormatException e) {            System.out.println(qq + "号含有字母");            return false;        }        return true;    }}

可以看到使用了正则表达式后,代码变得非常简洁。

二.正则表达式简介

正则表达式就是描述字符排列模式的一种自定义的语法规则。

正则表达式也称为模式表达式,自身具有一套非常完整的、可以编写模式的语法体系,提供了一种灵活且直观的字符串处理方法。正则表达式通常构建具有特定规则的模式,与输入的字符串信息比较,在特定的函数中使用从而实现字符串的匹配、查找、替换及分割等操作。下例中给出了三个模式,都是按照正则表达式的语法规则构建的。如下所示:

不要被上例中看似乱码的的字符串给吓退,他们都是按照正则表达式的语法规则构建的模式,是一种由普通字符和具有特殊功能的字符组成的字符串。而且要将这些模式字符串,放在特定的正则表达式函数中使用才有效果。

正则表达式定义了字符串的模式。正则表达式可以用来搜索、编辑或处理文本。正则表达式并不仅限于某一种语言,但是在每种语言中有细微的差别。Java正则表达式和Perl的是最为相似的。

三.正则表达式的语法规则

正则表达式描述了字符串匹配的模式,通过这个模式在特定的函数中对字符串进行匹配、查找、替换及分割等操作。正则表达式作为一个匹配的模板,是由原子(普通字符,例如字符a到z)、有特殊功能的字符(称为元字符,例如*、+和?等),以及模式修正符三部分组成的文字模式。一个最简单的正则表达式模式中,至少也要包含一个原子,如“/a”。而且在与perl兼容的正则表达式函数中使用模式时,一定要给模式加上定界符,即将模式包含在两个反斜线”/”之间。

1.定界符

在程序语言中,使用与Perl兼容的正则表达式,通常都需要将模式表达式放入定界符之间。作为定界的字符也不仅仅局限于使用斜线“/”。除了字母、数字和反斜线”\”以外的任何字符都可以作为定界符号。例如“#”、”!“、”{}“和”|“等都是可以的。通常习惯都将模式表达式包含在两个斜线”\“之间。

2.原子

原子是正则表达式最基本的单位。而且在每个模式中最少要包含一个原子。原子是由所有那些未显示指定为元字符的打印和非打印字符组成,笔者在这里将其详细划分为5类进行介绍。

1.普通字符作为原子

普通字符是编写正则表达式最常用的原子了,包括所有的大写和小写字母字符、所有的数字等。例如:a-z,A-Z,0-9.

/5/’用于匹配字符串中是否有5这个字符出现'/php/'用于匹配字符串中是否有php字符串出现

2.一些特殊字符和元字符作为原子
任何一个符号都可以作为原子使用,但如果这个符号在正则表达式中有一些特殊意义,我们就必须使用转意符号”\“取消它的特殊意义,将其变成一个普通的原子。例如,所有标点符号以及一些其他符号,双引号””“、单引号“’”、”*“、”+“、”.”等,如果当原子,就必须像\”、\’、*、+和.这样使用。

‘/./’用于匹配字符串中是否有英文的”.“出现

3.一些非打印字符作为原子

所谓的非打印字符,是一些在字符串中的格式控制符号,例如空格、回车及制表符号等。

举个例子:
’/\n/‘在windows系统中用于匹配字符串中是否有回车换行出现

4.使用”通用字符类型“作为原子

前面介绍的不管是打印字符还是非打印字符作为原子,都是一个原子只能匹配一个字符。而有时我们需要一个原子作为匹配一类字符,例如,匹配所以数字而不是一个数字,匹配所有字母而不是一个字母,这时就要使用”通用字符类型“了。共有六种通用字符类型。如下图所示:

\d 匹配任意一个十进制数字,等价于[0-9]
\D 匹配任意一个除十进制数字以外的字符,等价于[^0-9]
\s
\S
\w 匹配任意一个数字字母下划线
\W 与\w正好相反

5.自定义原子表([])作为原子

”通用字符类型“太少了,并不能涵盖我们需要的。例如数字中的奇数(1,3,5,7,9)、字母中的元音字母(a\e\i\o\u)等等。所以就需要我们可以自己定义出特定的类原子。使用原子表”[]“就可以定义一组彼此地位平等的原子,且从原子表中仅选择一个原子进行匹配。如下所示:

’/[apj]sp‘ 可以匹配asp、psp、jsp三种,从原子表中仅选择一个作为原子

还可以使用”^“和”-“.

3.元字符(量词)

所谓元字符就是用于构建正则表达式的具有特殊含义的字符,例如*+?等。在一个正则表达式中,元字符不能单独出现,他必须是用来修饰原子的。如果要在正则表达式中包含元字符本身,使其失去特殊的意义,则必须在前面加上\进行转意。

构造正则表达式的方法和创建数学表达式的方法相似,就是多种元字符与操作符将小的表达式结合在一起来创建更大的表达式。正则表达式的组件可以是单个的字符、字符集合、字符范围、字符间的选择或者所有这些组件的任意组合。元字符是组成正则表达式的最重要的部分。

更详细可以找资料。

4.模式修正符

模式修正符号在正则表达式定界符之外使用(最后一个斜线/之后),例如/php/i,其中/php是一个正则表达式的模式,而i就是修正此模式所使用的修正符号,用来在匹配时不区分大小写。模式修正符可以调整正则表达式的解释,扩展了正则表达式在匹配、替换等操作时的某些功能,而且模式修饰符号也可以组合在一起使用。模式修饰符对编写简洁而简小的表达式大有帮助。

具体有哪些可以查资料。

如i、m、x、e等

四.java中对正则表达式的支持(api)

Java正则表达式的类在 java.util.regex 包中,包括三个类:Pattern,Matcher 和 PatternSyntaxException。

Pattern对象是正则表达式的已编译版本。他没有任何公共构造器,我们通过传递一个正则表达式参数给公共静态方法 compile 来创建一个pattern对象。

Matcher是用来匹配输入字符串和创建的 pattern 对象的正则引擎对象。这个类没有任何公共构造器,我们用patten对象的matcher方法,使用输入字符串作为参数来获得一个Matcher对象。然后使用matches方法,通过返回的布尔值判断输入字符串是否与正则匹配。
如果正则表达式语法不正确将抛出PatternSyntaxException异常。

1.Pattern类的方法

Pattern是Java语言中的正则表达式对象。要使用正则表达式,首先必须从字符串“编译”出Pattern对象,这需要用到Pattern.compile(String regex)方法。

Pattern pattern = Pattern.compile("a.b+");

如果要指定匹配模式,可以在表达式中使用(?modifier)修饰符指定,也可以使用预定义常量。下面的两个Pattern对象的生成方法不同,结果却是等价的。

Pattern pattern = Pattern.compile("(?i)a.b+");Pattern pattern = Pattern.compile("a.b+",Pattern.CASE_INSENSITIVE);

如果要同时指定多种模式,可以连写模式修饰符,也可以直接用|运算符将预定义常量连接起来,以下两个Pattern对象也是等价的。

Pattern pattern = Pattern.compile("(?is)a.b+");Pattern pattern = Pattern.compile("a.b+",Pattern.CASE_INSENSITIVE | Pattern.DOTALL);

Pattern常用方法

  1. static boolean matches(String regex.CharSequence input)

这个方法可以检验字符串input能否由正则表达式regex匹配,因为是静态方法,所以不需要编译生成各个对象,方便随手使用。要注意的是,它检验的是“整个字符串能否由表达式匹配”,而不是“表达式能否在字符串中找到匹配”。你可以认为regex的首尾自动加上了匹配字符串起始和结束位置的锚点 \A和\z 。

Pattern.matches("\\d{6}","a123456");   //falsePattern.matches("\\d{6}","123456");     //true
  1. String[] split(CharSequence text)

通常,Pattern对象需要配合下面将要介绍的Matcher一起完成正则操作。如果只用正则表达式来切分字符串,只用Pattern的这个方法也可以。

这个方法接收的参数类型是CharSequence它可能有点陌生,其实它是String的父类,其他子类还有CharBuffer,StringBuffer,StringBuilder,因而可以应对常见的各种表示“字符串”的类。下面的代码仅以String为例:

String s = "2010-12-20";Pattern pattern = Pattern.compile("\\s+");for(String part : pattern.split(s)){    System.out.println(part);}
  1. String[] split(CharSequence text,int limit)

这个方法与上面的方法很相似,只是多了一个参数limit,它用来限定返回的String数组的最大长度。也就是说,它规定了字符串至多只能“切”limit-1次。如果不需要对字符串比较大,进行尽可能多的切分,使用这个方法。

String s = " 2010-12-20  ";Pattern pattern = Pattern.compile("\\s+");for(String part : Pattern.split(s,2)){    System.out.println(part);}
  1. static String quote(String text)

这个方法用来取消字符串text中所有转义字符的特殊含义,实质就是在字符串首尾添加 \Q 和 \E。通常,如果需要把某个字符串作为没有任何特殊意义的正则表达式(比如从外界读入的字符串,用在某个复杂的正则表达式中),就可以使用这个方法:

"aacb".matches("a*.b");            //true"a*.b".matches("a*.b");             //false"a*.b".matches("a*.b");             //false"a*.b".matches(Pattern.quote("a*.b"));        //true

2.Matcher类的方法

Matcher可以理解为“某次具体匹配的结果对象”:把编译好的Pattern对象“应用”到某个String对象上,就获得了作为“本次匹配结果”的Matcher对象。之后,就可以通过它获得关于匹配的信息。

Pattern pattern = Pattern.compile("\\d{4}-\\d{2}-\\d{2}");Matcher matcher = pattern.matcher("2010-12-20 2011-02-14");while(matcher.find()){    System.out.println(matcher.group());}

对编译好的Pattern对象调用matcher(String text)方法,传入要匹配的字符串text,就得到了Matcher对象,每次调用一次find()方法,如果返回true,就表示“找到一个匹配”,此时可以通过下面的若干方法获得关于本次匹配的信息。

  1. String group(int n)

返回当前匹配中第n对捕获括号捕获的文本,如果n为0,则取匹配的全部内容;如果n小于0或者大于最大分组编号数,则报错。

  1. String group()

返回当前匹配的全部文本,相当于group(0)。

  1. int groupCount()

返回此Matcher对应Pattern对象中包含的捕获分组数目,编号为0的默认分组不计在内。

  1. int start(n)

返回当前匹配中第n对捕获括号匹配的文本在原字符串中的起始位置。

  1. int start()

返回当前匹配的文本在原字符串中的起始位置,相当于start(0)。

  1. int end(n)

返回当前匹配中第n对捕获括号匹配的文本在原字符串中的结束位置。

  1. int end()

返回当前匹配的文本在原字符串中的结果位置,相当于end(0)。

  1. String replaceAll(String replacement)

如果进行正则表达式替换,一般用到的是Matcher的replaceAll()方法,它会将原有文本中正则表达式能匹配的所有文本替换为replaceement字符串。

3.String

许多时候只需要临时使用某个正则表达式,而不需要重复使用,这时候每次都生成Pattern对象和Matcher对象再操作显得很烦琐。所以,Java的String类提供了正则表达式操作的静态成员方法,只需要String对象就可以执行正则表达式操作。

  1. boolean matches(String regex)

这个方法判断当前的string对象能否由正则表达式regex匹配。请注意,这里的“匹配”指的并不是regex能否在String内找到匹配,而是指regex匹配整个String对象,因此非常适合用来做数据校验。

"123456".matches("\\d{6}");            //true"a123456".matches("\\d{6}");          //true2. String replaceFirst(String regex,String replacement)

这个方法用来替换正则表达式regex在字符串中第一次能匹配的文本,可以在replacement字符串中用$num引用regex中对应捕获分组匹配的文本。

"2010-12-20 2011-02-14".replaceFirst("(\\d{4})-(\\d{2})-(\\d{2})","$2/$3/$1");3. String replaceAll(String regex,String replacement)

这个方法用来进行所有的替换,它的结果等同于Matcher类的replaceAll()方法,replacement字符串中也可以用$num的表示法引用regex中对应捕获分组匹配的文本。

"2010-12-20 2011-02-14".replaceAll("(\\d{4})-(\\d{2})-(\\d{2})","$2/$3/$1");4. String[] split(String regex)

这个方法等价于Pattern中对应的split()方法,此处不再赘述。

  1. String[] split(String regex,int limit)

这个方法等价于Pattern中对应的split()方法,此处不再赘述。

五.难点是啥

正则表达式最大的难点在于熟练书写正则表达式。

六.参考资料

Java正则表达式教程及示例
http://www.importnew.com/6810.html

Java正则表达式API
http://my.oschina.net/fhd/blog/370833

Java魔法堂:深入正则表达式API
https://yq.aliyun.com/articles/31723

0 0
原创粉丝点击