首页 > 程序开发 > 软件开发 > Java >

Java开发之正则表达式解析

2017-11-02

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

Java开发之正则表达式解析。

正则表达式简介

概述

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

特点

正则表达式的特点是:

灵活性、逻辑性和功能性非常的强;可以迅速地用极简单的方式达到字符串的复杂控制。可读性比较差。

组成

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

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

语法格式

//写正则表达式
String regex = "(.*)(\\d+)(.*)";
// 将给定的正则表达式编译到模式中。
Pattern pattern = Pattern.compile(regex);
//匹配字符串
Matcher matcher = pattern.matcher("This order was placed for QT3000! OK?");
matcher.find();   //得到matcher后可以使用一系列方法:find、group、replaceAll。。。。。


正则表达式的构造摘要

\

\

\

\

\

\

\

\

\

\

Pattern标记

Pattern类的静态方法 :static Pattern compile(String regex, int flags)

将给定的正则表达式编译到具有给定标志的模式中。

其中的flags参数就是Pattern标记,这个标记在某些时候非常重要。

Pattern.CANON_EQ: 启用规范等价。Pattern.CASE_INSENSITIVE: 启用不区分大小写的匹配。Pattern.COMMENTS: 模式中允许空白和注释。Pattern.DOTALL : 启用 dotall 模式。Pattern.LITERAL : 启用模式的字面值分析。Pattern.MULTILINE: 启用多行模式。Pattern.UNICODE_CASE: 启用 Unicode 感知的大小写折叠。Pattern.UNIX_LINES: 启用 Unix 行模式。

正则的功能:

字符串匹配

matches 和lookingAt 方法都用来尝试匹配一个输入序列模式。它们的不同是matcher要求整个序列都匹配,而lookingAt 不要求。这两个方法经常在输入字符串的开始使用。Matcher判断整个字符序列与模式是否匹配。当连续用Matcher对象检查多个字符串时候,可以使用Matcher.reset():重置匹配器,放弃其所有显式状态信息并将其添加位置设置为零。也可以使用Matcher.reset(CharSequence input) 重置此具有新输入序列的匹配器来重复使用匹配器。

//匹配功能
String telphone = "17612345678";
//[358]表示这个字符是3、5或8,[0-9]表示这个字符为0到9,{9}表示出现正好9次
String regex = "1[358][0-9]{9}";
//匹配,返回值为布尔类型(也就是判断字符串是否符合这个正则表达式)
boolean flag = telphone.matches(regex);
System.out.println(flag);

String str = "heheeeeeeeeeee";
//+号表示e出现1次或者多次
String regex1 = "hehe+";
//判断是否匹配
boolean matches = str.matches(regex1);
System.out.println(matches);

打印结果:

false
true


public class RegexMatches {
    private static final String REGEX = "foo";
    private static final String INPUT = "fooooooooooooooooo";
    private static Pattern pattern;
    private static Matcher matcher;

    public static void main(String args[]) {
        pattern = Pattern.compile(REGEX);
        matcher = pattern.matcher(INPUT);

        System.out.println("Current REGEX is: " + REGEX);
        System.out.println("Current INPUT is: " + INPUT);

        System.out.println("lookingAt(): " + matcher.lookingAt());
        System.out.println("matches(): " + matcher.matches());
    }
}

打印结果:

Current REGEX is: foo
Current INPUT is: fooooooooooooooooo
lookingAt(): true
matches(): false

字符串的切分

String[] split(String regex)

根据给定的正则表达式的匹配来拆分此字符串。

String[] split(String regex, int limit)

根据匹配给定的正则表达式来拆分此字符串。

当然,还有一个StringTokenizer类,可以用来切分字符串,但是现在SUN已经不推荐使用了。转变下思路,其实用正则表达式也可以达到将字符串切分为段的目的。

简单的:

String str = "one:two:three:four:five";
//使用 : 符号分割字符串
String[] split = str.split(":");
for (String s : split) {
    System.out.println(s);
}

打印结果:

one
two
three
four
five

较为复杂的:

// 使用 Pattern split() method
// "\\W": 表示非[a-zA-Z_0-9]的字符
Pattern pattern = Pattern.compile("\\W");
String[] words = pattern.split("one@two#three:four$five");
//遍历打印
for (String s : words) {
    System.out.println("Pattern.split  : " + s);
}

打印结果:

Pattern.split  : one
Pattern.split  : two
Pattern.split  : three
Pattern.split  : four
Pattern.split  : five


字符串的替换

String.replace(char oldChar, char newChar)

返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 而生成的。

String.replace(CharSequence target, CharSequence replacement)
使用指定的字面值替换序列替换此字符串匹配字面值目标序列的每个子字符串。
String.replaceAll(String regex, String replacement)
使用给定的 replacement 字符串替换此字符串匹配给定的正则表达式的每个子字符串。
String.replaceFirst(String regex, String replacement)
使用给定的 replacement 字符串替换此字符串匹配给定的正则表达式的第一个子字符串。
StringBuffer.replace(int start, int end, String str)
使用给定 String 中的字符替换此序列的子字符串中的字符。
StringBuilder.replace(int, int, java.lang.String)
使用给定 String 中的字符替换此序列的子字符串中的字符。
Matcher.replaceAll(String replacement)
替换模式与给定替换字符串相匹配的输入序列的每个子序列。
Matcher.replaceFirst(String replacement)
替换模式与给定替换字符串匹配的输入序列的第一个子序列。

简单的:

String str = "one:two:three:four:five";
//使用 : 符号分割字符串
String s1 = str.replace(":","000");
//第一个参数为正则表达式
String s2 = str.replaceAll(":", "000");
System.out.println(s1);
System.out.println(s2);

打印结果:

one000two000three000four000five
one000two000three000four000five

较复杂的:

// "\\W": 表示非[a-zA-Z_0-9]的字符
Pattern pattern = Pattern.compile("\\W");
Matcher matcher = pattern.matcher("one@two#three:four$five");
//替换匹配到的第一个
System.out.println(matcher.replaceFirst("000"));
//替换匹配到的所有元素
System.out.println(matcher.replaceAll("000"));

打印结果:

one000two#three:four$five
one000two000three000four000five


appendReplacement 和 appendTail 方法

Matcher 类也提供了appendReplacement 和appendTail 方法用于文本替换:

看下面的例子来解释这个功能:

public class RegexMatches1
{
    private static String REGEX = "a*b";
    private static String INPUT = "aabfooaabfooabfoob";
    private static String REPLACE = "-";
    public static void main(String[] args) {
        Pattern p = Pattern.compile(REGEX);
        // 获取 matcher 对象
        Matcher m = p.matcher(INPUT);
        StringBuffer sb = new StringBuffer();
        while(m.find()){
            //替换
            m.appendReplacement(sb,REPLACE);
        }
        m.appendTail(sb);
        System.out.println(sb.toString());
    }
}

打印结果:

-foo-foo-foo-


字符串捕获

捕获组是把多个字符当一个单独单元进行处理的方法,它通过对括号内的字符分组来创建。

例如,正则表达式(dog) 创建了单一分组,组里包含"d","o",和"g"。

捕获组是通过从左至右计算其开括号来编号。例如,在表达式((A)(B(C))),有四个这样的组:

((A)(B(C)))(A)(B(C))(C)

可以通过调用matcher对象的groupCount方法来查看表达式有多少个分组。groupCount方法返回一个int值,表示matcher对象当前有多个捕获组。

还有一个特殊的组(组0),它总是代表整个表达式。该组不包括在groupCount的返回值中。

//group用法
public class RegexMatches {
    public static void main(String args[]) {

        // 按指定模式在字符串查找
        String line = "This order was placed for QT3000! OK?";
        String pattern = "(.*)(\\d+)(.*)";

        // 创建 Pattern 对象
        Pattern r = Pattern.compile(pattern);

        // 现在创建 matcher 对象
        Matcher m = r.matcher(line);
        System.out.println(m.groupCount());
        if (m.find()) {
            System.out.println("Found value: " + m.group(0));
            System.out.println("Found value: " + m.group(1));
            System.out.println("Found value: " + m.group(2));
        } else {
            System.out.println("NO MATCH");
        }
    }
}
private static void test2() {
    String str = "aa1234bb7672cc";

    //1:对指定规则进行编译,获取一个模式对象
    Pattern compile = Pattern.compile("aa(\\d+)bb([0-9]+)cc");
    //2:使用这个模式对字符串进行匹配,返回一个匹配的对象
    Matcher matcher = compile.matcher(str);
    //3:使用这个macher对象,可以具体的进行匹配操作,然后获取匹配的结果
    if(matcher.find()){
        String group = matcher.group();
        String group2 = matcher.group(0);//和不传参数一样,都是获取整个正则表达式匹配的内容
        String group3 = matcher.group(1);//获取正则表达式中第一个正则组的内容
        String group4 = matcher.group(2);//.......
        System.out.println("group:"+group);
        System.out.println("group2:"+group2);
        System.out.println("group3:"+group3);
        System.out.println("group4:"+group4);
    }
}

打印结果:

group:aa1234bb7672cc
group2:aa1234bb7672cc
group3:1234
group4:7672


综合示例:

public class RegexExamples {

    public static void main(String[] args) {
        // 使用 pattern with flags
        Pattern pattern = Pattern.compile("ab", Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher("ABcabdAb");

        // 使用 Matcher find(), group(), start() 和 end() 方法
        while (matcher.find()) {
            System.out.println("Found the text \"" + matcher.group()
                    + "\" starting at " + matcher.start()   //匹配到的元素的开始下标索引
                    + " index and ending at index " + matcher.end());   //匹配到的元素截止下标索引加1
        }

        // 使用 Pattern split() 方法
        pattern = Pattern.compile("\\W");
        String[] words = pattern.split("one@two#three:four$five");
        for (String s : words) {
            System.out.println("Split using Pattern.split(): " + s);
        }

        // 使用 Matcher.replaceFirst() 和 replaceAll() 方法
        //  *号表示前面的1出现0次或者多次
        pattern = Pattern.compile("1*2");
        matcher = pattern.matcher("11234512678");
        //使用 _ 号替换掉所有匹配到的元素
        System.out.println("Using replaceAll: " + matcher.replaceAll("_"));
        //使用 _ 号替换掉第一个匹配到的元素
        System.out.println("Using replaceFirst: " + matcher.replaceFirst("_"));

        //使用 capturing group
        //   \\1 表示第一组:(\\w\\d)的简写
        System.out.println(Pattern.matches("(\\w\\d)\\1", "a2a2")); //true
        System.out.println(Pattern.matches("(\\w\\d)\\1", "a2b2")); //false
        //   \\2 表示第二组:(B\\d)的简写   \\1 表示第一组:(AB)的简写
        System.out.println(Pattern.matches("(AB)(B\\d)\\2\\1", "ABB2B2AB")); //true
        System.out.println(Pattern.matches("(AB)(B\\d)\\2\\1", "ABB2B3AB")); //false
    }

}

打印结果:

Found the text "AB" starting at 0 index and ending at index 2
Found the text "ab" starting at 3 index and ending at index 5
Found the text "Ab" starting at 6 index and ending at index 8
Split using Pattern.split(): one
Split using Pattern.split(): two
Split using Pattern.split(): three
Split using Pattern.split(): four
Split using Pattern.split(): five
Using replaceAll: _345_678
Using replaceFirst: _34512678
true
false
true
False


异常

PatternSyntaxException 类的方法

PatternSyntaxException 是一个非强制异常类,它指示一个正则表达式模式中的语法错误。

PatternSyntaxException 类提供了下面的方法来帮助我们查看发生了什么错误。

public String getDescription()

获取错误的描述。

public int getIndex()
获取错误的索引。
public String getPattern()
获取错误的正则表达式模式。
public String getMessage()
返回多行字符串,包含语法错误及其索引的描述、错误的正则表达式模式和模式中错误索引的可视化指示。

正则表达式实例应用

1.验证用户名和密码:("^[a-zA-Z]\w{5,15}$")正确格式:"[A-Z][a-z]_[0-9]"组成,并且第一个字必须为字母6~16位;

2.验证电话号码:("^(\\d{3,4}-)\\d{7,8}$")正确格式:xxx/xxxx-xxxxxxx/xxxxxxxx;、

3.验证手机号码:"^1[3|4|5|7|8][0-9]\\d{8}$";

4.验证身份证号(15位或18位数字):"\\d{14}[[0-9],0-9xX]";

5.验证Email地址:("^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$");

6.只能输入由数字和26个英文字母组成的字符串:("^[A-Za-z0-9]+$") ;

7.整数或者小数:^[0-9]+([.][0-9]+){0,1}$

8.只能输入数字:"^[0-9]*$"。

9.只能输入n位的数字:"^\d{n}$"。

10.只能输入至少n位的数字:"^\d{n,}$"。

11.只能输入m~n位的数字:"^\d{m,n}$"。

12.只能输入零和非零开头的数字:"^(0|[1-9][0-9]*)$"。

13.只能输入有两位小数的正实数:"^[0-9]+(.[0-9]{2})?$"。

14.只能输入有1~3位小数的正实数:"^[0-9]+(\.[0-9]{1,3})?$"。

15.只能输入非零的正整数:"^\+?[1-9][0-9]*$"。

16.只能输入非零的负整数:"^\-[1-9][0-9]*$"。

17.只能输入长度为3的字符:"^.{3}$"。

18.只能输入由26个英文字母组成的字符串:"^[A-Za-z]+$"。

19.只能输入由26个大写英文字母组成的字符串:"^[A-Z]+$"。

20.只能输入由26个小写英文字母组成的字符串:"^[a-z]+$"。

21.验证是否含有^%&',;=?$\"等字符:"[%&',;=?$\\^]+"。

22.只能输入汉字:"^[\u4e00-\u9fa5]{0,}$"。

23.验证URL:"^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$"。

24.验证一年的12个月:"^(0?[1-9]|1[0-2])$"正确格式为:"01"~"09"和"10"~"12"。

25.验证一个月的31天:"^((0?[1-9])|((1|2)[0-9])|30|31)$"正确格式为;"01"~"09"、"10"~"29"和“30”~“31”。

26.获取日期正则表达式:\\d{4}[年|\-|\.]\d{\1-\12}[月|\-|\.]\d{\1-\31}日?

评注:可用来匹配大多数年月日信息。

27.匹配双字节字符(包括汉字在内):[^\x00-\xff]

评注:可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1)

28.匹配空白行的正则表达式:\n\s*\r

评注:可以用来删除空白行

29.匹配HTML标记的正则表达式:<(\S*?)[^>]*>.*?|<.*? />

评注:网上流传的版本太糟糕,上面这个也仅仅能匹配部分,对于复杂的嵌套标记依旧无能为力

30.匹配首尾空白字符的正则表达式:^\s*|\s*$

评注:可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式

31.匹配网址URL的正则表达式:[a-zA-z]+://[^\s]*

评注:网上流传的版本功能很有限,上面这个基本可以满足需求

32.匹配帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$

评注:表单验证时很实用

33.匹配腾讯QQ号:[1-9][0-9]{4,}

评注:腾讯QQ号从10 000 开始

34.匹配中国邮政编码:[1-9]\\d{5}(?!\d)

评注:中国邮政编码为6位数字

35.匹配ip地址:([1-9]{1,3}\.){3}[1-9]。

评注:提取ip地址时有用

36.匹配MAC地址:([A-Fa-f0-9]{2}\:){5}[A-Fa-f0-9]

相关文章
最新文章
热点推荐