关于正则表达式

136 阅读7分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情

介绍

正则表达式 regular expression,简称 regex。由一些字母、字符以及特殊字符组成的字符串,通过该字符串去匹配一些子串,或是搜索子串,或是替换子串,来完成一系列的操作。

JDK API 中 java.util.regex 包,提供了 Java 自带的正则表达式的接口、类和异常类。

图片描述

核心类主要是 Pattern 和 Matcher 。

Pattern 类被 final 修饰的,说明该类中的所有方法可以使用,但不能被重写,该类中提供了正则所有的规则。我们可以根据规则制定出所需的模式来。

Matcher 类也是被 final 修饰的,主要提供一系列字符串匹配查询的方法。

以下是正则中的保留字符:

保留字符说明
()把圆括号内外的表达式区分开。
[]方括号内的字符之间是 “或” 的关系。
{}花括号内填写的数字,表示表达式匹配的次数。
对竖线前后字符做 “或” 运算。
-横线前后的字符,表示两个字符之间的所有连续字符。
\反斜杠对保留字符做转义,保留自身符号。

以下是相对常用的规则

匹配符说明
[abc]包含字母 a 或 b 或 c。
[^abc]不包含字母 a 或 b 或 c 的其他字母。
[a-zA-Z]包含字母 a - z 和 A - Z 范围内的。
[0-9]包含 0 - 9 数字的。
.表示任意字符(除换行符 \n 外) 。
\d等价于 [0-9]。
\s表示任意空白符,等价于[ \t\n\x0B\f\r] 这些符号。
\S表示除空白符以外的所有字符。
\w等价于 [a-zA-Z_0-9]。

以下限定符的说明:

符号说明
是否出现。
*出现 0 或多次。
+出现 1 或多次。
{n}n 表示出现的次数,表达式出现 n 次。
{n,}表达式至少出现 n 次。
{n,m}表达式至少出现 n 次,最多出现 m 次。

现在给出这样一个192.168.9字符串,来书写能匹配的正则表达式:

如果是ip,第一位不能是0,所以[1-9],第二位和第三位可以是 [0-9] 的数字,但是第二位和第三位可以有也可以没有,所以我们限定出现次数至少 0 次最多 2 次 ,这里用 点 分割,但是在正则表达式中点表示除换行符以外的所有字符,所以我们需要转换 \.0 - 9 的数字我们可以采用 \d 符号来表示更为简化,当然也可以使用 \p{Digit} 这是 POSIX 字符类,在使用时符号前面还需要再加一个 `` 转义才可以

答案:[1-9][0-9]{0,2}\\.\\d[1,3]\\.\\{Digit}

ip 地址,如果整个字符串都要匹配,那么就需要这样写

[a-z]{2}:([1-9][0-9]{0,2}\.\d{1,3}\.\p{Digit}{1,3}\.\d{1,3},?)+

那么在 Java 中如何使用正则表达式完成匹配操作呢?

主要使用 java.util.regex 包中的 Pattern 和 Matcher 类进行操作。

Matcher 类没有提供构造方法,那么它的实例如何获取呢?

可以通过 Pattern 类中的 matcher() 方法来获取哦。 😮

public Matcher matcher(CharSequence input),该方法不是静态方法,必须先获取到 Pattern 实例后,才能调用。

Matcher 类中常用的匹配方法: 👇

方法说明
public boolean matches()提供的正则表达式完成匹配时返回 true,否则返回 false。
public boolean find()提供的正则表达式只要有部分匹配就返回 true。
public String group()提取匹配的子串信息。
public int start()返回匹配子串的开始索引。
public int end()返回匹配子串的结束索引。

使用:

根据给定的正则表达式获取 Pattern 类对象 Pattern p = Pattern.compile(regex);

通过 Pattern 类中的 matcher() 方法获取 Matcher 类对象 Matcher m = p.matcher(input);

当输入字符串中的内容完全匹配,则打印输出 if(m.matches())

当输入的字符串只能部分匹配时,则一部分一部分打印输出 while(m.find())

import......
public class TestRegex {
    /**
     * 正则表达式进行数据验证的操作
     * @param regex 正则表达式
     * @param input 匹配的数据信息
     */
    public void method1(String regex,String input) {
        // 根据给定的正则表达式获取 Pattern 类对象
        Pattern p = Pattern.compile(regex);
        // 通过 Pattern 类中的 matcher() 方法获取 Matcher 类对象
        Matcher m = p.matcher(input);
        // 当输入字符串中的内容完全匹配,则打印输出
        if(m.matches()) {
            System.out.println(m.group());
        }else {
            // 当输入的字符串只能部分匹配时,则一部分一部分打印输出
            while(m.find()) {
                System.out.println(m.group()+"   start index: "+m.start()+"   end index: "+m.end());
            }
        }
    }
    public static void main(String[] args) {
        TestRegex tr = new TestRegex();
        tr.method1("[1-9][0-9]{0,2}\.\d{1,3}\.\p{Digit}{1,3}\.\d{1,3}", "ip:192.168.9.12,127.0.0.1");
        tr.method1("[a-z]{2}:([1-9][0-9]{0,2}\.\d{1,3}\.\p{Digit}{1,3}\.\d{1,3},?)+", "ip:192.168.9.12,127.0.0.1");
    }
} 

正则表达式搜索和替换

我们也可以通过正则表达式进行搜索和替换操作,Matcher 类中提供了替换的方法如下:

  • public Matcher appendReplacement(StringBuffer sb, String replacement)
  • public StringBuffer appendTail(StringBuffer sb)
public void method2() { 
// 提供字符串,将字符串中的子串java,奇数为小写,偶数为大写 
String s = "Java jAva test java JAVa JaVa hello low JavA JAVA CoCo"; 
// flags 标记位设置为 Pattern.CASE_INSENSITIVE,表示匹配 java 时忽略大小写。
Pattern p = Pattern.compile("java",Pattern.CASE_INSENSITIVE);
// 将字符串根据模式进行匹配
Matcher m = p.matcher(s);
// 创建字符串缓冲区 
StringBuffer buffer = new StringBuffer();
int i = 0;
while(m.find()) { 
i++; 
// 将找到的 java 字符串进行替换 m.appendReplacement(buffer, i%2==0?"JAVA":"java"); 
}
// 将数据追加放入字符串缓冲区中 m.appendTail(buffer); 
// 将字符串缓冲区打印输出 System.out.println(buffer); 
}
public static void main(String[] args) { 

TestRegex tr = new TestRegex(); tr.method2();
}

字符串的匹配、查找、替换和分割

正则表达式是匹配字符串的一类逻辑式,通过代表特定含义的保留字符,能够描述符合规则的一组字符串,在字符串中运用正则表达式常用于字符串的分割与匹配校验。

字符串的匹配、查找、替换和分割是企业项目中不可缺少的部分,经常需要进行一些列处理后进行存储。

然而自付出的匹配、查找、替换和分割,往往都是离不开正则表达式的使用。

以下是 String 类中提供需要使用正则表达式的方法:

方法说明
public boolean matches(String regex)根据 regex 进行匹配,能匹配返回 true,否则返回 false。
public String replaceFirst(String regex, String replacement)根据 regex 进行查找,找到后进行替换第一个匹配的字符串。
public String replaceAll(String regex, String replacement)根据 regex 进行查找,找到后进行替换全部匹配的字符串。
public String[] split(String regex)根据 regex 分割字符串,将分割后的数据存储在 String 数组中。

接下来,我们一个个来看一下:

  1. String 类中提供的 matches() 方法。

    该方法其实源码中访问的是 Pattern.matches(regex, str),使用代码如下:

String str = "abcdeeeabcefg";
str.matches("(abc.*)+");  --> 返回 true
  1. String 类中提供的 replaceFirst() 和 replaceAll() 方法。

    这两个替换方法其实源码中访问的是:

    Pattern.compile(regex).matcher(str).replaceFirst(replacement)

    Pattern.compile(regex).matcher(str).replaceAll(replacement)

    使用代码如下:

String str = "abcdeeeabcefg";
str.replaceFirst("abc", "小桃子");  --> 返回字符串:小桃子deeeabcefg
str.replaceAll("ab.{2}", "企鹅");  --> 返回字符串:企鹅eee企鹅fg
  1. String 类中提供的 split () 方法

    分割方法在源码中也是访问 Pattern 类中的方法,Pattern.compile(regex).split(str) ,使用代码如下:

String str2 = "hello|你好|123|test|java";
String[] ss = str2.split("\|");

str2 = "hello,你好,123,test,java";
ss = str2.split(",");

符号中 “ | ” 需要转义才能使用,不过也可以这样写 \s*\|\s* ,而 “ , ” 无须转义直接可用。

对于字符串的分割操作,split() 方法的执行效果是比较低的。

在企业项目中,我们对字符串进行分割会使用的是 StringTokenizer 类,它存放在 java.util 包中。

StringTokenizer 类中空格是默认分割符:

StringTokenizer st = new StringTokenizer("this is a string");

如果是其他的分割符,则需要指定:

StringTokenizer st = new StringTokenizer("this|is|a|string", "|");
StringTokenizer st = new StringTokenizer("this,is,a,string", ",");