Java 正则表达式

介绍

前段时间使用Java的正则表达式做一些字符串匹配的任务,现将学到的正则表达式的知识整理成文。

Java中Spring.class涉及到正则表达式。如Spring.split(), matches(),replaceAll()等方法。

Java中更一般使用正则表达式的方式是利用Pattern.class和Matcher.class,所在package为java.util.regex

Java中正则表达式相关API使用不难掌握,不过重点在于编写合适的正则表达式,尤其是利用字符类和量词的使用。

正则表达式

Java中正则表达式与之前使用的Python是有区别的,区别在于Java对于反斜线(\)处理的不同。
在Python中"\d"表示 匹配一位数字(0-9),而Java中匹配一位数字(0-9),需要的正则表达式为"\\d"。
不过换行符和制表符只需要单反斜线“\n\t”。

字符

给出构造正则表达式的常用字符

字符描述
B指定字符B
\xhh十六进制值为oxhh的字符
\uhhhh十六进制值为oxhhhh的Unicode字符
\ttab
\n换行
\r回车
\e转义

字符类

字符类在编写正则表达式起到重要的作用,我们给出一些常用的构造正则表达式的字符类。

字符类描述
. (小数点)任意字符
[abc][ ] 中括号,包含a,b,c中任意字符
[^abc][ ]中括号加^, 表示否定,除a,b,c之外的
[a-z]从a到z的任意字符
[a-z&&[hi]]&&表示交集,即包含h或i
\s空白字符,包含空格,换行,回车,tab,换页
\S大写为小写的取反,非空白字符,等价于[^\s]
\d数字0-9
\D非数字,等价于[^0-9]
\w词字符,数字,大小写字母,等价于[0-9a-zA-Z]
\W非词,等价于[^\w]

逻辑操作符

组合一个或多个表达式,通过逻辑操作符实现。

逻辑操作符描述
XYY跟在X后面,并且XY同时满足
X|YX或者Y
(X)() 小括号表示捕获组(group),可以对group进行处理,尤其是获取其中的内容

边界匹配符

针对边界的匹配,给出边界匹配符。

边界匹配符描述
^一行的开始
$一行的结束
\b词的边界

量词

量词描述了一个模式匹配文本的方式,包含

  • 贪婪型:量词默认是贪婪的,发现尽可能多的匹配
  • 勉强型:通过问号(?)指定,匹配最小的字符数,也称为懒惰型,最少匹配,非贪婪。
  • 占有型:通过加号(+)指定,当用于字符串时防止匹配失败时回溯。
贪婪型勉强型占有型描述
X?X??X?+匹配0个或1个X
X*X*?X*+匹配0个或多个X
X+X+?X++匹配1个或多个X
X{n}X{n}?X{n}+恰好匹配n个X
X{n,}X{n,}?X{n,}+至少匹配n个X
X{n,m}X{n,m}?X{n,m}+至少匹配n个X,最多匹配m个X

正则表达式使用

String

String.class提供了一些方法,如用于切分的split()方法,用于验证是否匹配的matches()方法,用于替换操作的replaceAll方法。简单示例如下:

	/**
     * String中正则表达式的测试
     *
     * @throws Exception 异常情况
     */
    @Test
    public void testStringRegex() throws Exception {

        // split
        // 结果:[some, examples, of, regex, test]
        String query = "some examples of regex test";
        String[] parts = query.split(" ");
        System.out.println(Arrays.toString(parts));

        // matches 整个字符串是否匹配
        // 结果:false
        String regex = "regex";
        boolean isMatched = query.matches(regex);
        System.out.println(isMatched);

        // replaceAll
        // 结果:some <REGEX> examples <REGEX> of <REGEX> regex <REGEX> test
        String replaceQuery = " <REGEX> ";
        String newQuery = query.replaceAll(" ", replaceQuery);
        System.out.println(newQuery);
    }

Pattern和Matcher

正则表达式更一般的用法是使用*java.util.regex.*下的Matcher和Pattern类。

通过Pattern类的静态方法static Pattern.compile() 编译正则表达式,利用Pattern的*matcher()*方法生产Matcher对象。根据Matcher对象提供的API完成相应的操作。

我们以获取字符串中的电话号码和Html中的标题为例,实现正则表达式的匹配。示例如下:

package com.notepad.thinkingnote.regexes;

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

/**
 * Description: 正则表达式
 * <p>
 * Create:      2018/8/25 21:37
 *
 * @author Marvin Yang
 */
public class RegexUtils {

    /**
     *  获取content中全部的手机号码
     *
     * @param content 待匹配内容
     * @return 电话号码集合
     */
    public List<String> getPhoneNumber(String content) {
        List<String> phoneNumbers = new ArrayList<>();
        Matcher matcher = PHONE_PATTERN.matcher(content);
        while (matcher.find()) {
            // group=2对应(1\\d{10}), 匹配的值即为手机号码
            phoneNumbers.add(matcher.group(2));
        }
        return phoneNumbers;
    }

    /**
     * 从Html中获取title
     *
     * @param content a html
     * @return the title of a html
     */
    public String getHtmlTitle(String content) {
        Matcher matcher = TITLE_PATTERN.matcher(content);
        return matcher.find()? matcher.group(1):null;
    }

    /** 手机号码 */
    private static final String PHONE_REGEX = "(^|\\D)(1\\d{10})($|\\D)";
    private static final Pattern PHONE_PATTERN;

    /** html 标题 */
    private static final String HTML_TITLE_REGEX = "<title>(.*?)</title>";
    private static final Pattern TITLE_PATTERN;

    static {
        PHONE_PATTERN = Pattern.compile(PHONE_REGEX);
        
        // 不区分大小写
        TITLE_PATTERN = Pattern.compile(HTML_TITLE_REGEX, Pattern.CASE_INSENSITIVE);
    }
}

构造单测样例如下:

package com.notepad.thinkingnote.regexes;

import org.junit.Test;

import java.util.Arrays;
import java.util.List;

import static org.junit.Assert.*;

/**
 * Description: 正则表达式单测
 * <p>
 * Create:      2018/8/25 21:45
 *
 * @author Marvin Yang
 */
public class RegexUtilsTest {

    private RegexUtils regexUtils = new RegexUtils();

    @Test
    public void getPhoneNumber() {
        // test 1: 有电话号码
        String content = "紧急情况请拨打13845697569";
        List<String> phoneNumbers = regexUtils.getPhoneNumber(content);
        System.out.println(String.format("[%s] has phone number : [%s]", content, phoneNumbers));

        // test 2: 数字12位
        content = "紧急情况请拨打138456975690";
        phoneNumbers = regexUtils.getPhoneNumber(content);
        System.out.println(String.format("[%s] has phone number : [%s]", content, phoneNumbers));

        // test 3: 开头不是1
        content = "紧急情况请拨打23845697569";
        phoneNumbers = regexUtils.getPhoneNumber(content);
        System.out.println(String.format("[%s] has phone number : [%s]", content, phoneNumbers));

        // test 4: 数字在开头
        content = "13845697569紧急情况请拨打";
        phoneNumbers = regexUtils.getPhoneNumber(content);
        System.out.println(String.format("[%s] has phone number : [%s]", content, phoneNumbers));
    }

    @Test
    public void getHtmlTitle() throws Exception {
        // test 1: 正常情况
        String content = "<title>学而不厌 诲人不倦 - 第 1 页 - CSDN博客</title>";
        String title = regexUtils.getHtmlTitle(content);
        System.out.println(String.format("get title [%s] from content: [%s]", title, content));


        // test 1: 不区分大小写
        content = "<TITLE>学而不厌 诲人不倦 - 第 1 页 - CSDN博客</TITLE>";
        title = regexUtils.getHtmlTitle(content);
        System.out.println(String.format("get title [%s] from content: [%s]", title, content));
    }
}

总结

本文对Java的正则表达式的使用进行了简单的介绍,已经利用Pattern和Matcher进行匹配的样例。当然重要的还是正则表达式的编写,不一定非得很复杂, 重点是适合我们处理的问题。

参考文献

Java编程思想第四版 第十三章

  • 43
    点赞
  • 244
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值