JAVA 正则表达式

1. 定义

1.1 基础定义
  • 正则表达式定义了字符串的模式
  • 正则表达式可以用来搜索、编辑或处理文本
  • 正则表达式并不仅限于编程语言,但是在每种编程语言中有细微差别
1.2 Java中的正则表达式

​ 在Sun的JDK1.4版本中,JAVA自带了支持正则表达式的包,即java.util.regex包

2. 基础

2.1 元字符
代码 说明
. 匹配除换行符以外的任意字符(linux:\n win:\r\n)
\w 匹配字母或数字或下划线或汉字
\s 匹配任何空白字符,是[ \t\n\x0b\r\f](开头有空格)的简写
\d 匹配数字,是[0-9]的简写
^ 匹配字符串的开始
$ 匹配字符串的结束
\b 匹配字符串的结束
2.2 重复
代码/语法 说明
* 重复零次或更多次(任意次)
+ 重复一次或更多次(至少一次)
? 重复零次或一次(至多一次)
重复n次
重复n次或更多次
重复n到m次
2.3 字符类
  • 匹配自定义字符集,如:[.?!]匹配标点字符"."或"?"或"!"
  • [0-9]与\d等同
  • [a-z0-9A-Z_]与\w等同(仅考虑英文)
2.4 分支条件

使用|把不同的规则分别表示

如:0\d{2}-\d{8}|0\d{3}-\d{7}这个表达式能匹配两种连字符号分割的电话号码,一种是三位区号,8位本地号(如012-87654321);一种是4位区号,7位本地号(如:0123-7654321)

2.5 反义
代码/语法 说明
\W 匹配任意不是字母、数字、下划线、汉字的字符,等同于[^\w]
\S 匹配任意不是空白的字符
\D 匹配任意不是数字的字符
\B 匹配不是单词开头或结束的位置
[^x] 匹配除了x以外的任意字符
[^aeiou] 匹配除了aeiou这几个字母以外的任意字符
2.6 复选例子
  • [abc] 复选集定义,匹配a,b,c
  • [^abc]匹配除了a,b,c以外的所有字符
  • [a-d1-7]范围匹配,匹配字母a-d和数字1-7的单字符,即不匹配d1
2.7 分组和反向引用

小括号()可以达到对正则表达式进行分组的效果。

模式分组后会在正则表达式中创建反向引用。反向引用会保存匹配模式分组的字符串片段,这使得我们可以获取并使用这个。字符串片段。

在以正则表达式替换字符串的语法中,是通过$来引用分组的反向引用,$0是匹配完整模式的字符串(注意在JavaScript中是用$&表示);$1是第一个分组的反向引用;$2是第二个分组的反向引用,以此类推。

示例:

    @Test
    public void regexGroup(){
        // 去除单词与“.”和","之间的空格
        String str = "Hello , World .";
        String pattern = "(\\w)(\\s)([.,])";
        // $0匹配“(\w)(\s)([.,])”,结果为“o.空格,”和“d空格.”
        // $1匹配“(\w)” 结果为“o”和“d”
        // $2匹配”(\s)“ 结果为”空格“和”空格“
        // $3匹配”([.,])“ 结果为”,“和”.“

        //Hello, World.
        System.out.println(str.replaceAll(pattern,"$1$3"));
        //Hello(hhh), World(hhh).
        System.out.println(str.replaceAll(pattern,"$1(hhh)$3"));

    }

上面的例子中,使用了[.]来匹配普通字符”.“,而不是使用[\\.]。因为正则表达式[]中的".",会自动处理为[\.],即普通字符"."来处理。

2.8 分组的反向引用副本

Java中可以使用"?"将小括号中匹配的内容保存为一个名字为name的副本

    @Test
    public void name(){
        String str = "@Vitcou nice to meet you";
        //String str = "@Vitcou @123 nice to meet you";
        // 保存一个副本
        Pattern pattern = Pattern.compile("@(?<first>\\w+\\s+)");
        Matcher matcher = pattern.matcher(str);
        while (matcher.find()){
            System.out.println(matcher.group());
            System.out.println(matcher.group(1));
            System.out.println(matcher.group(0));
            System.out.println(matcher.group("first"));
        }
    }
@Vitcou 
Vitcou 
@Vitcou 
Vitcou 
2.9 指定正则表达式的模式

可以在正则表达式使用修饰符指定模式

  • (?i)正则表达式忽略大小写
  • (?s)表示单行模式("single line mode"),使用正则的"."表达式匹配所有字符,包括换行符
  • (?m)表示多行模式("multi-line mode"),使用正则的"^"和"$"匹配字符串每行的开始和结束
2.10 易错点示例
  • [jpg|png]代表匹配j或p或g或p或n或g中的任意字符
  • (jpg|png)代表匹配jpg或png

3. Java中字符串正则表达式处理方法

3.1 处理方法

在Java中String有四个内置的运行正则表达式的方法,分别是matchers()、split()、replaceFirst(pattern,replacement)、replaceAll(pattern,replacement)

方法 描述
str.matches("pattern") 仅当正则匹配整个字符串时返回true
str.split("pattern") 按照匹配的正则表达式切片字符串
str.replaceFirst("pattern","replacement") 替换第一个匹配的字符串片段
str.replaceAll(”pattern",“replacement”) 替换所有匹配的字符串片段
3.2 代码示例
    @Test
    public void javaRegexTest(){
        System.out.println("vitcou".matches("vitcou"));
        System.out.println("---------------");

        String[] array = "v i t c o u".split("\\s");
        for (String s : array) {
            System.out.println(s);
        }
        System.out.println("---------------");

        System.out.println("v i t c o u".replaceFirst("\\s","-"));
        System.out.println("---------------");

        System.out.println("v i t c o u".replaceAll("\\s","-"));
        System.out.println("---------------");
    }

4. 模式和匹配

Java中使用正则表达式需要使用到两个类

import java.util.regex.Matcher;
import java.util.regex.Pattern;

第一步,通过正则表达式创建模式对象Pattern;

第二步,通过模式对象Pattern,根据指定字符串匹配对象Matcher;

第三步,通过匹配对象Matcher,根据正则表达式操作字符串;

示例代码:

    @Test
    public void patternAndMatcher(){
        String str = "Hello Vitcou";
        String regex = "\\w+";
        Pattern pattern = Pattern.compile(regex);
        // Java中忽略大小写的两种写法
        //Pattern pattern = Pattern.compile("\\w+",Pattern.CASE_INSENSITIVE);
        // 推荐写法
        //Pattern pattern = Pattern.compile("(?i)\\w+");

        Matcher matcher = pattern.matcher(str);
        // 遍历所有匹配的序列
        while (matcher.find()){
            System.out.println("start:"+matcher.start()+"---"+"end:"+matcher.end());
            System.out.println("group:"+matcher.group());
        }

        // 创建两个模式,将空格替换为"---"(将匹配内容替换成指定内容)
        Pattern replace = Pattern.compile("\\s+");
        Matcher matcher2 = replace.matcher(str);
        System.out.println("after replace:"+matcher2.replaceAll("---"));
    }

5. 参考例子

5.1 中文字匹配
    @Test
    public void regexChinese(){
        String str = "你所做的便是你所拥有的";
        //Pattern pattern = Pattern.compile("[\\u4e00-\\u9fa5]");
        Pattern pattern = Pattern.compile("[\\u4e00-\\u9fa5]+");
        Matcher matcher = pattern.matcher(str);
        while (matcher.find()){
            System.out.println(matcher.group());
        }
    }
5.2 数字匹配
    @Test
    public void numbers(){
        String str = "1990\n2009\n2017";
        // 这里应用了 (?m) 的多行匹配模式,只为方便我们测试输出
        // "^1990$|^199[1-9]$|^20[0-1][0-6]$|^2017$" 为判断 1990-2017 正确的正则表达式
        // 这里也说明匹配语法是单个字符
        Pattern pattern = Pattern.compile("(?m)^1990$|^199[1-9]$|^200[0-9]$|^201[0-6]$|^2017$");
        Matcher matcher = pattern.matcher(str);
        while (matcher.find()) {
            System.out.println(matcher.group());
        }
    }
5.3 贪婪与非贪婪模式匹配标签内内容

贪婪与非贪婪模式影响的是被量词修饰的子表达式的匹配行为,贪婪模式在整个表达式匹配成功的前提下,尽可能多的匹配,而非贪婪模式在整个表达式匹配成功的前提下,尽可能少的匹配。非贪婪模式只被部分NFA引擎所支持。

属于贪婪模式的量词,也叫做匹配优先量词,包括:

“{m,n}”、“{m,}”、“?”、“*”和“+”。

在一些使用NFA引擎的语言中,在匹配优先量词后加上“?”,即变成属于非贪婪模式的量词,也叫做忽略优先量词,包括:

“{m,n}?”、“{m,}?”、“??”、“*?”和“+?”。

从正则语法的角度来讲,被匹配优先量词修饰的子表达式使用的就是贪婪模式,如“(Expression)+”;被忽略优先量词修饰的子表达式使用的就是非贪婪模式,如“(Expression)+?”。

参考示例:

    @Test
    public void greedy(){
        String str = "<div>文章标题</div><div>发布时间</div>";
        // 贪婪模式
        Pattern pattern = Pattern.compile("<div>(?<title>.+)</div>");
        Matcher matcher = pattern.matcher(str);
        while (matcher.find()) {
            System.out.println(matcher.group("title"));
        }

        System.out.println("--------------");

        // 非贪婪模式,在匹配优先量量词后面加上"?",即变成非贪婪模式的量词,也叫忽略优先量词
        pattern = Pattern.compile("<div>(?<title>.+?)</div>");
        matcher = pattern.matcher(str);
        while (matcher.find()) {
            System.out.println(matcher.group("title"));
        }
    }
文章标题</div><div>发布时间
--------------
文章标题
发布时间

参考:

[1] [Java 正则表达式详解]: https://segmentfault.com/a/1190000009162306
[2] [正则表达式(Java版整理)]: https://www.cnblogs.com/yw0219/p/8047938.html
[3] [正则表达式之 贪婪与非贪婪模式详解]: https://www.cnblogs.com/520yang/articles/7473596.html

posted @ 2020-07-28 01:30  维柯Vitcou  阅读(156)  评论(0编辑  收藏  举报