在Java中使用正则表达式

我对正则表达式的理解

正则表达式Regex(Regular Expression),是一种通过定义由特定字符组成的表达式来对字符串进行匹配、查找、替换和切割的字符串操作工具。

正则表达式中特定的一些字符

表达式 匹配内容
字符
x 字符 x
\\ 反斜线字符
\0n 带有八进制值 0 的字符 n (0 <= n <= 7)
\0nn 带有八进制值 0 的字符 nn (0 <= n <= 7)
\0mnn 带有八进制值 0 的字符 mnn(0 <= m <= 3、0 <= n <= 7)
\xhh 带有十六进制值 0x 的字符 hh
\uhhhh 带有十六进制值 0x 的字符 hhhh
\t 制表符 (‘\u0009’)
\n 新行(换行)符 (‘\u000A’)
\r 回车符 (‘\u000D’)
\f 换页符 (‘\u000C’)
\a 报警 (bell) 符 (‘\u0007’)
\e 转义符 (‘\u001B’)
\cx 对应于 x 的控制符
字符类
[abc] a、b 或 c(简单类)
[^abc] 任何字符,除了 a、b 或 c(否定)
[a-zA-Z] a 到 z 或 A 到 Z,两头的字母包括在内(范围)
[a-d[m-p]] a 到 d 或 m 到 p:[a-dm-p](并集)
[a-z&&[def]] d、e 或 f(交集)
[a-z&&[^bc]] a 到 z,除了 b 和 c:[ad-z](减去)
[a-z&&[^m-p]] a 到 z,而非 m 到 p:[a-lq-z](减去)
预定义字符类
. 任何字符(与行结束符可能匹配也可能不匹配)
\d 数字:[0-9]
\D 非数字: [^0-9]
\s 空白字符:[ \t\n\x0B\f\r]
\S 非空白字符:[^\s]
\w 单词字符:[a-zA-Z_0-9]
\W 非单词字符:[^\w]
边界匹配器
^ 行的开头
$ 行的结尾
\b 单词边界
\B 非单词边界
\A 输入的开头
\G 上一个匹配的结尾
\Z 输入的结尾,仅用于最后的结束符(如果有的话)
\z 输入的结尾
Greedy数量词
X? X,一次或一次也没有
X* X,零次或多次
X+ X,一次或多次
X{n} X,恰好 n 次
X{n,} X,至少 n 次
X{n,m} X,至少 n 次,但是不超过 m 次

正则表达式在Java中的表现形式

public final class Pattern
extends Object
implements Serializable

Pattern正则表达式的编译表示形式。

指定为字符串的正则表达式必须首先被编译为此类的实例。然后,可将得到的模式用于创建 Matcher 对象,依照正则表达式,该对象可以与任意字符序列匹配。执行匹配所涉及的所有状态都驻留在匹配器中,所以多个匹配器可以共享同一模式。

因此,典型的调用顺序是

 Pattern p = Pattern.compile("a*b");
 Matcher m = p.matcher("aaaaab");
 boolean b = m.matches();

在仅使用一次正则表达式时,可以方便地通过此类定义 matches 方法。此方法编译表达式并在单个调用中将输入序列与其匹配。语句

 boolean b = Pattern.matches("a*b", "aaaaab");

等效于上面的三个语句,尽管对于重复的匹配而言它效率不高,因为它不允许重用已编译的模式。

使用正则表达式对字符串进行匹配

使用正则表达式对字符串进行匹配有三种方式:
1)使用字符串的对象的matches()方法
2)使用Matcher的对象的matches()方法
3)使用Pattern类的matches()方法
匹配的特点:
1)根据正则表达式的规则对整个字符串进行匹配
2)匹配结果返回对应的布尔值
使用方法:
请参考下面匹配字符串是否为电话号码的实例

public class MatchTest {

    public static void main(String[] args) {
        System.out.println("一,使用字符串的对象的matches()方法");
        matchDemo_1("13805646681");
        matchDemo_1("03805646681");
        matchDemo_1("13805Jia681");
        matchDemo_1("138056");

        System.out.println("二,使用Matcher的对象的matches()方法");
        matchDemo_2("13805646681");
        matchDemo_2("03805646681");
        matchDemo_2("13805Jia681");
        matchDemo_2("138056");

        System.out.println("三,使用Pattern类的matches()方法");
        matchDemo_3("13805646681");
        matchDemo_3("03805646681");
        matchDemo_3("13805Jia681");
        matchDemo_3("138056");
    }

    /**
     * 匹配字符串是否为电话号码
     * 匹配规则:
     * 1.电话号码以数字1开头
     * 2.电话号码长度为11
     * 3.电话号码为全数字
     * 对应的正则表达式:
     * 1)"1\\d{10}"
     * 解读:
     *      正则表达是第一个数是1,所以它只能匹配以1开头的字符串;
     *      \\d,因为Java中反斜杠会把它后面的字符进行转移,所以\\d就是正则表达式中预定义字符类中的\d(== [0-9]),即能够匹配数字0-9中的任意一个;
     *      {10},代表前面的\d恰好出现10次,这样加上第一个数1共有11个数字,所以它只能匹配长度为11且全部为数字的字符串。
     * 2)"1[0-9]{10}"
     * 解读:
     *      \d == [0-9]
     */
    public static void matchDemo_1(String str) {
        String regex = "1\\d{10}";
        boolean isMatched = str.matches(regex);
        System.out.println(str + (isMatched ? "是电话号码" : "不是电话号码"));
    }

    public static void matchDemo_2(String str) {
        String regex = "1[0-9]{10}";
        // 1,将正则表达式编译成Pattern对象
        Pattern p = Pattern.compile(regex);
        // 2, 与字符串进行关联,生成Matcher对象
        Matcher m = p.matcher(str);
        // 3,对字符串进行操作
        boolean isMatched = m.matches();
        System.out.println(str + (isMatched ? "是电话号码" : "不是电话号码"));
    }

    public static void matchDemo_3(String str) {
        String regex = "1\\d{10}";
        boolean isMatched = Pattern.matches(regex, str);
        System.out.println(str + (isMatched ? "是电话号码" : "不是电话号码"));
    }
}

使用正则表达式对字符串进行替换

正则表达式既可以替换字符串中所有匹配到的字符,也可以只替换第一次匹配到的字符,对应的两个方法是replaceALL和replaceFirst,同样在String对象和Matcher对象中都包含这两个方法。
替换的特点:
1)可以将正则表达式匹配到的字符(串)替换为你指定的字符(串)
2)替换结果生成新的字符串
使用方法:
请参考下面叠词替换的实例

public class StackedWordsReplace {
    public static void main(String[] args) {
        stackedWordsReplaceDemo_1();
        stackedWordsReplaceDemo_2();
    }

    public static void stackedWordsReplaceDemo_1() {
        // 将下面的字符串转换成"我要学习编程。"
        String str = "我我我我我要要学学学编编编编程程程程。";

        // 正则表达式中通过()创建一个捕获组
        // 捕获组默认从1开始进行编号,可以通过从左到右计算开括号(左括号)个数和顺序进行排序
        // 例如,在表达式 ((A)(B(C))) 中,存在四个这样的组:((A)(B(C)))、(A)、(B(C))、(C)
        // 正则表达式中的\n和$n分别在匹配环节和替换环节中引用捕获组捕获的内容,n代表数字1、2、3...
        // "(.)\1+"解读:
        // .可以匹配任意字符,\\1即\1引用(.)的捕获内容,+前面的字符出现一次或多次。
        // 比如,当.匹配的到我的时候\1就是我,所以这个表达式能够匹配到无数个我连续组成但最低不少两个我的字符串。
        // $1为替换的类容,因为$1引用(.)的捕获内容,所以当.匹配到什么就替换为什么
        str = str.replaceAll("(.)\\1+", "$1");

        System.out.println(str);
    }

    public static void stackedWordsReplaceDemo_2() {
        String str = "我我我我我要要学学学编编编编程程程程。";
        String regex = "(.)\\1+";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(str);
        str = matcher.replaceAll("$1");
        System.out.println(str);
    }
}

使用正则表达式对字符串进行切割

使用正则表达式对字符串进行切割有两种方式:
1)使用String对象的split方法
2)使用Pattern对象的split方法
切割的特点:
1)可以将正则表达式匹配到的字符(串)作为分隔符来对字符串进行切割
2)切割结果为子串组成的字符串数组
使用方法:
请参考下面的切割实例

public class SplitTest {
    public static void main(String[] args) {
        splitDemo_1();
        splitDemo_2();
    }

    public static void splitDemo_1() {
        // 将下面的字符串以.为分隔符进行切割
        // 由于在正则表达式中.为预定义字符,所以需要用\进行转义,
        // 在Java中\也是转义字符,所以仍需要进行转义
        String str = "我.爱.中.国";
        String regex = "\\.";
        String[] strings = str.split(regex);
        for (String s : strings) {
            System.out.println(s);
        }
    }

    public static void splitDemo_2() {
        String str = "我.爱.中.国";
        String regex = "\\.";
        Pattern pattern = Pattern.compile(regex);
        String[] strings = pattern.split(str);
        for (String s : strings) {
            System.out.println(s);
        }
    }
}

综合案例演示

下面将演示综合使用和切割来对IP地址进行排序

public class IPSort {

    public static void main(String[] args) {
        ipSort();
    }

    /**
     * 将IP地址进行排序
     */
    public static void ipSort() {
        String ip = "127.0.0.1 192.168.0.1 114.114.114.114 8.8.8.8 10.2.33.134 255.255.255.255";

        // 1.将IP地址全部替换为xxx.xxx.xxx.xxx样式
        ip = ip.replaceAll("\\w{1,3}", "00$0"); // 将IP地址每一段都添加00
        System.out.println(ip);
        ip = ip.replaceAll("0*(\\w{3})", "$1"); // 去除每一段多余的0,是每一段只保留三位数字
        System.out.println(ip);

        // 2.对字符串进行排序
        String[] arr = ip.split(" ");
        System.out.println(Arrays.toString(arr));
        Arrays.sort(arr);
        for (String s : arr) {
            // 去除添加的0
            s = s.replaceAll("0*(\\w+)", "$1");
            System.out.println(s);
        }
    }
}

使用正则表达式对字符串进行查找

对字符串进行查找,主要用的是Matcher对象的以下方法:
1)find()尝试查找与该模式匹配的输入序列的下一个子序列
2)group()返回上一次匹配操作所匹配的输入子序列
3)reset(CharSequence input)将该模式应用到新的输入序列
查找的特点:
1)可以将正则表达式匹配到的字符(串)逐个找出来
2)查找结果为一个个匹配的子串
3)必须逐个查找,直接调用group()方法无法得到结果
使用方法:
请参考下面的爬去网页中的电子邮箱实例

public class FindEmail {

    public static void main(String[] args) {
        findEmail();
    }

    public static void findEmail() {
        // 简单邮箱匹配规则
        String reg = "\\w+@\\w+(\\.\\w+)+";
        // 1.将正则表达式编译成Pattern对象
        Pattern p = Pattern.compile(reg);
        Matcher m = null;
        try {
            URL url = new URL("https://www.douban.com/group/topic/70867518/");
            URLConnection connection = url.openConnection();
            BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String line = null;
            while ((line = br.readLine()) != null) {
                // 2.将字符串和Pattern对象进行关联,生成Matcher对象
                if (m == null) {
                    m = p.matcher(line);
                } else {
                    m.reset(line);
                }
                // 3.通过Matcher对象对字符串进行操作
                while (m.find()) {
                    System.out.println(m.group());
                }
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/miracle_yan/article/details/77170411