java 正则表达式学习笔记

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_25673113/article/details/79590595

概述

正则表达式能够解决各种字符串处理的问题:匹配选择编辑以及验证。正则表达式是一种强大灵活的文本处理工具,在很多语言中都支持正则表达式。本文主要介绍的是java的正则表达式的使用。

基础

在正则表达式中我们要表示一个数字,可以用\d表示。但是java对\的处理和其他语言不同。其他语言中\表示 要在正则表达式中插入一个字面上的反斜线,没有特殊含义,而在java中,\表示 我要在正则表达式中插入一个反斜线,其后面的字符具有特殊的含义。 所以java中,你要表示数字就是\d,要表示一个字面上的反斜线就是\\。当然换行和制表符除外:\n\t。
以下是是特殊字符代表的含义。
这里写图片描述
这里写图片描述
这里写图片描述
例子:

public class Test {
    public static void main(String[] args) {
        //判断数字
        System.out.println("asda".matches("\\d+"));

        //?是存在一个或零个之前的符号
        System.out.println("2321".matches("-?\\d+"));
        System.out.println("+2321".matches("-?\\d+"));

    }
}
/*
false
true
false
 */

Pattern 类

上面的例子是String自带的正则验证,还有一个更强大的替换工具,而且具有更佳的性能。
那就是 java.util.regex.Patternjava.util.regex.Matcher,String内部也是使用了这个类来实现

第一步,通过正则表达式创建模式对象 Pattern。
第二步,通过模式对象 Pattern,根据指定字符串创建匹配对象 Matcher。
第三步,通过匹配对象 Matcher,根据正则表达式操作字符串。
例子1:

匹配模式

有三种匹配方式,叫做贪婪型,非贪婪型,占有型。对于这三种匹配模式也有叫: “最大匹配Greedy”``“最小匹配Reluctant”``“完全匹配Possessive”

贪婪 勉强 侵占 含义
X? X?? X?+ 匹配 X 零次或一次
X* X*? X*+ 匹配 X 零次或多次
X+ X+? X++ 匹配 X 一次或多次
X{n} X{n}? X{n}+ 匹配 X n 次(这个应该不存在这几种模式,就是固定匹配n个)
X{n,} X{n,}? X{n,}+ 匹配 X 至少 n 次
X{n,m} X{n,m}? X{n,m}+ 匹配 X 至少 n 次,但不多于 m 次

从上表可以看出贪婪型是默认的匹配方式,勉强型是在贪婪型后面加上?,占有型是在贪婪型后面加上+。

Greediness(贪婪型):也叫最大匹配

例如你要用 “<.+>”去匹配“aaavaabb”,也许你所期待的结果是想匹配 “”,但是实际结果却会匹配到“aava”。这是为什么呢?下面我们跟踪下最大匹配的匹 配过程。

①“<”匹配字符串的“<”。
②“.+”匹配字符串的“tr>aavaab”,在进行最大匹配时,它把两个 “>”都匹配了,它匹配了所有字符,直到文本的最后字符“b”③这时,发现不能成功匹配“>”,开始按原路回退,用“a”与“>”匹 配,直到“ab”前面的“>”匹配成功。

Reluctant(Laziness)(勉强型):最小匹配

最小匹配意味者,.+? 匹配一个字符后,马上试一试>的匹配可能,失败了,则.+?再匹配一个字符,再马上试一试>的匹配可能。JDK文档中Greedy 和Reluctant,它是以eat一口来隐喻的,所以翻译成贪吃和(勉强的)厌食最贴切了。不过我喜欢最大匹配、最小匹配的说法。

Possessive(占有型):完全匹配

与最大匹配不同,还有一种匹配形式:X?+、X*+、X++、X{n}+、X{n,}+、X{n,m}+等,成为完全匹配。它和最大匹配一样,一直匹配所有的字符,直到文本的最后,但它不原路返回。

这个不大好理解,有一个例子摘自http://bbs.csdn.net/topics/390269371比较形象:
字符串为aaa,正则表达式为[a]+,这是一个贪婪的匹配,直接返回aaa。但是如果是占有型的,正则为[a]+a,返回结果是false,是空。
如果a*a,是匹配优先的,也就是说先匹配,如果正则的后续部分不能再匹配,就回溯,在这个例子中,匹配字符串aaa的时候,首先a匹配到最后一个,然后发现正则后面还有一个a没法匹配,就会将a*回溯到字符串的中间一个a,这时候正则中的最后一个a与字符串的最后一个a正好匹配,匹配结束。

如果正则是a*+a,+是占有优先,也就是说+前面的字符会尽可能匹配,匹配了的就不会再回溯,不会让回去了,即所谓占有。如果字符串是aaa,那么这个例子中匹配过程就是a*+匹配了字符串的三个a,正则中的最后一个a不会再被匹配,因为a*+不会回溯。

来源:http://blog.csdn.net/xh16319/article/details/27498287


例子:(特殊提醒在正则表达式中[,左中括号是特殊字符,所以要加\,]右中括号不是特殊字符所以不用加\):

String str = "This is [google][1],this is [apple][2],and this is [ms][3]";
//贪婪匹配
Pattern pattern1 = Pattern.compile("\\[.*]");
Matcher matcher1 = pattern1.matcher(str);
while (matcher1.find()) {
    System.out.println(matcher1.group());
}
System.out.println("----------");
//非贪婪匹配
Pattern pattern2 = Pattern.compile("\\[.*?]");
Matcher matcher2 = pattern2.matcher(str);
while (matcher2.find()) {
    System.out.println(matcher2.group());
}
System.out.println("----------");
//独占匹配
String str1 = "[google1]";
//下面两种会有不同的而结果,因为.*是占有的他先会把所有符合的匹配光,所以第一个匹配时str1中的]会被匹配在.*中,当匹配后面]的时候没有字符给他匹配了。
//Pattern pattern3 = Pattern.compile("\\[.*+]");
Pattern pattern3 = Pattern.compile("\\[.*+");
Matcher matcher3 = pattern3.matcher(str1);
while (matcher3.find()) {
    System.out.println(matcher3.group());
}

由于三种方式匹配的规则不同,有着不同的计算量,所以引发的问题:一个有正则表达式引发的血案 http://zhuanlan.51cto.com/art/201708/549051.htm

分组和标签

正则表达式还有一个分组的功能。(a)((b)(c))当用这个当做正则表达是匹配的时候,每个括号都可以当做一个组。组号为从左到右左括号出现的个数,0代表全部。group()或者group(0)代表全部,group(1)为(a), group(2)为((b)(c)),group(3)为(b),group(3)为(c)。
比如:

public static void test3() {
        String str = "1111bbbbbb    ccccc22222";
        //贪婪匹配
        Pattern pattern1 = Pattern.compile("(\\d+)([a-zA-Z]+)(\\s+)([a-zA-Z]+)(\\d+)");
        Matcher matcher1 = pattern1.matcher(str);
        while (matcher1.find()) {
            System.out.println("group():" + matcher1.group());
            System.out.println("group(0):" + matcher1.group(0));
            System.out.println("group(1):" + matcher1.group(1));
            System.out.println("group(2):" + matcher1.group(2));
            System.out.println("group(3):" + matcher1.group(3));
            System.out.println("group(4):" + matcher1.group(4));
        }

    }

还通过?<name>对组进行命名。

//对组1和组2进行命名
public static void test4() {
        String str = "1111bbbbbb    ccccc22222";
        //贪婪匹配
        Pattern pattern1 = Pattern.compile("(?<name1>\\d+)(?<name2>[a-zA-Z]+)(\\s+)([a-zA-Z]+)(\\d+)");
        Matcher matcher1 = pattern1.matcher(str);
        while (matcher1.find()) {
            System.out.println("group():" + matcher1.group("name1"));
            System.out.println("group(0):" + matcher1.group("name2"));
        }

    }

在线工具以及常用的正在表达式

参考资料:

猜你喜欢

转载自blog.csdn.net/qq_25673113/article/details/79590595