Java字符串 正则表达式详解

目录
  • 一、规则表
    • 1.字符
    • 2.字符类 .
    • 3.边界匹配符
    • 4.逻辑操作符
    • 5.量词
  • 二、Pattern类
    • 1.Pattern类的实例获取—compile方法
    • 2.split方法
    • 3.Pattern中匹配标记参数
  • 三、Matcher类
  • 总结

在日常Java后端开发过程中,免不了对数据字段的解析,自然就少不了对字符串的操作,这其中就包含了正则表达式这一块的内容,这里面涉及Java包中Pattern类和Macher类,本篇博客就针对这一块内容和常见的用法进行总结,本博客主要的参考资料是《Java编程思想》第4版。

以一个问题引出本博客的内容。问题是:检查一个字符串是否以大写字母开头,以句号结尾

String len="^[A-Z].*[\\.]$";
System.out.println("Taaa.".matches(len));//true
System.out.println("taaa.".matches(len));//false
System.out.println("Taaa".matches(len));//false

1.*[\.] 就 是 正 则 表 达 式 , 用 来 匹 配 字 符 串 。 代 表 一 行 的 起 始 , [ A − Z ] 表 是 A 到 Z 任 何 的 字 母 , 就是正则表达式,用来匹配字符串。^代表一行的起始,[A-Z]表是A到Z任何的字母, 就是正则表达式,用来匹配字符串。代表一行的起始,[A−Z]表是A到Z任何的字母,表示的一行的结束。

一、规则表

规则表定义正则表达式该怎么写。这类东西不需要刻意去记,用的时候去写就好,用多了自然就记住了。

1.字符

B 指定字符B
\xhh 十六进制为oxhh的字符
\uhhhh 十六进制表示为oxhhhh的Unicode字符
\t 制表符Tab
\n 换行符
\r 回车
\f 换页
\e 转义

2.字符类 .

. 任意字符
[abc] 包含a、b和c的任何字符(和a|b|c作用相同)
[^abc] 除了a、b和c之外的任何字符(否定)
[a-zA-Z] 从a到z或从A到Z的任何字符(范围)
[abc[hij]] 任意a、b、c、h、i和j字符(与a|b|c|h|i|j作用相同)
[a-z&&[hij]] 任意h、i或j
\s 空白符(空格、tab、换行、换页和回车)
\S 非空白符
\d 数字
\D 非数字
\w 词字符[a-zA-Z0-9]
\W 非词字符

3.边界匹配符

^ 一行的起始
$ 一行的结束
\b 词的边界
\B 非词的边界
\G 前一个匹配的结束

4.逻辑操作符

XY Y跟在X后面
X|Y X或Y
(X) 捕获组

5.量词

贪婪型 勉强型 占有型 如何匹配
X? X?? X?+ 一个或零个X
X* X*? X*+ 零个或多个X
X+ X+? X++ 一个或多个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}+ X至少n次,且不超过m次

二、Pattern类

1.Pattern类的实例获取—compile方法

1.下面主要是Pattern类源码下一些重要的方法

private Pattern(String p, int f) {
    pattern = p;
    flags = f;

    // to use UNICODE_CASE if UNICODE_CHARACTER_CLASS present
    if ((flags & UNICODE_CHARACTER_CLASS) != 0)
        flags |= UNICODE_CASE;

    // Reset group index count
    capturingGroupCount = 1;
    localCount = 0;

    if (!pattern.isEmpty()) {
        try {
            compile();
        } catch (StackOverflowError soe) {
            throw error("Stack overflow during pattern compilation");
        }
    } else {
        root = new Start(lastAccept);
        matchRoot = lastAccept;
    }
}

从Pattern类代码可以看出构造器是私有的,故无法使用new去获得Pattern类对象实例。

仔细查询Pattern类下代码后发现通过静态方法compile去获取Pattern类的实例对象。

public static Pattern compile(String regex) {
    return new Pattern(regex, 0);
}

通过compile方法生成一个Pattern类实例对象,然后将想要匹配的字段传入Pattern对象的matcher()方法,matcher()方法会返回生成一个Matcher类实例对象,这个对象也有很多对应的方法。所以Matcher类也是无法通过new去创建一个实例的,而是通过matcher方法

public Matcher matcher(CharSequence input) {
    if (!compiled) {
        synchronized(this) {
            if (!compiled)
                compile();
        }
    }
    Matcher m = new Matcher(this, input);
    return m;
}
public static boolean matches(String regex, CharSequence input) {
    Pattern p = Pattern.compile(regex);
    Matcher m = p.matcher(input);
    return m.matches();
}

所以之前博客开头那个问题,也可以用另外两种方式实现:

方式一:

Pattern len = Pattern.compile("^[A-Z].*[\\.]$");
Matcher matcher = len.matcher("Taaa.");
boolean matches = matcher.matches();
System.out.println(matches);

当是从源码中可以看出matches方法是类静态方法,所以没必要使用Macher类实例对象来调用方法。可以使用:

方式二:

System.out.println(Pattern.matches("^[A-Z].*[\\.]$","Taaa."));

2.split方法

下面是Split方法的源码:

public String[] split(CharSequence input, int limit) {
    int index = 0;
    boolean matchLimited = limit > 0;
    ArrayList<String> matchList = new ArrayList<>();
    Matcher m = matcher(input);

    // Add segments before each match found
    while(m.find()) {
        if (!matchLimited || matchList.size() < limit - 1) {
            if (index == 0 && index == m.start() && m.start() == m.end()) {
                // no empty leading substring included for zero-width match
                // at the beginning of the input char sequence.
                continue;
            }
            String match = input.subSequence(index, m.start()).toString();
            matchList.add(match);
            index = m.end();
        } else if (matchList.size() == limit - 1) { // last one
            String match = input.subSequence(index,
                                             input.length()).toString();
            matchList.add(match);
            index = m.end();
        }
    }

    // If no match was found, return this
    if (index == 0)
        return new String[] {input.toString()};

    // Add remaining segment
    if (!matchLimited || matchList.size() < limit)
        matchList.add(input.subSequence(index, input.length()).toString());

    // Construct result
    int resultSize = matchList.size();
    if (limit == 0)
        while (resultSize > 0 && matchList.get(resultSize-1).equals(""))
            resultSize--;
    String[] result = new String[resultSize];
    return matchList.subList(0, resultSize).toArray(result);
}

方法解析:

input:要拆分的字符序列;

limit:结果阈值;根据指定模式拆分输入序列。

limit参数作用:

limit参数控制应用模式的次数,从而影响结果数组的长度。

如果 n 大于零,那么模式至多应用 n- 1 次,数组的长度不大于 n,并且数组的最后条目将包含除最后的匹配定界符之外的所有输入。

如果 n 非正,那么将应用模式的次数不受限制,并且数组可以为任意长度。

如果 n 为零,那么应用模式的次数不受限制,数组可以为任意长度,并且将丢弃尾部空字符串。

详细讲解:假设 input=“boo:and:foo”,匹配符为"o",可知模式最多可应用4次,数组的长度最大为5;

1、当limit=-2时,应用模式的次数不受限制且数组可以为任意长度;推测模式应用4次,数组的长度为5,数组为{“b”,"",":and:f","",""};

2、当limit=2时,模式至多应用1次,数组的长度不大于 2,且第二个元素包含除最后的匹配定界符之外的所有输入;推测模式应用1次,数组的长度为2,数组为{“b”,“o:and:foo”};

3、当limit=7时,模式至多应用6次,数组的长度不大于 7;推测模式应用4次,数组的长度为5,数组为{“b”,"",":and:f","",""};

4、当limit=0时,应用模式的次数不受限制,数组可以为任意长度,并且将丢弃尾部空字符串;推测模式应用4次,数组的长度为3,数组为{“b”,"",":and:f"}。

这里m.find像迭代器,遍历输入字符串

3.Pattern中匹配标记参数

编译标记 效果
Pattern.CANON_EQ 启用规范等价。当且仅当两个字符的“正规分解(canonicaldecomposition)”都完全相同的情况下,才认定匹配。默认情况下,不考虑“规范相等性(canonical equivalence)”。
Pattern.CASE_INSENSITIVE 启用不区分大小写的匹配。默认情况下,大小写不敏感的匹配只适用于US-ASCII字符集。这个标志能让表达式忽略大小写进行匹配,要想对Unicode字符进行大小不敏感的匹配,只要将UNICODE_CASE与这个标志合起来就行了。
Pattern.COMMENTS 模式中允许空白和注释。在这种模式下,匹配时会忽略(正则表达式里的)空格字符(不是指表达式里的“\s”,而是指表达式里的空格,tab,回车之类)。注释从#开始,一直到这行结束。可以通过嵌入式的标志来启用Unix行模式。
Pattern.DOTALL 启用dotall模式。在这种模式下,表达式‘.'可以匹配任意字符,包括表示一行的结束符。默认情况下,表达式‘.'不匹配行的结束符。
Pattern.MULTILINE 启用多行模式。在这种模式下,‘^'和‘ ' 分 别 匹 配 一 行 的 开 始 和 结 束 。 此 外 , ‘ ' 仍 然 匹 配 字 符 串 的 开 始 , ‘ '分别匹配一行的开始和结束。此外,‘^'仍然匹配字符串的开始,‘ '分别匹配一行的开始和结束。此外,‘'仍然匹配字符串的开始,‘'也匹配字符串的结束。默认情况下,这两个表达式仅仅匹配字符串的开始和结束。
Pattern.UNICODE_CASE 启用Unicode感知的大小写折叠。在这个模式下,如果你还启用了CASE_INSENSITIVE标志,那么它会对Unicode字符进行大小写不敏感的匹配。默认情况下,大小写不敏感的匹配只适用于US-ASCII字符集。
Pattern.UNIX_LINES 启用Unix行模式。在这个模式下,只有‘\n'才被认作一行的中止,并且与‘.'、‘^'、以及‘$'进行匹配。

Pattern.CASE_INSENSITIVEPattern.COMMENTSPattern.MULTILINE这三个比较常用。

三、Matcher类

对照Matcher构造器源码,可知构造器将Pattern对象的引用赋于Matcher中变量parentPattern,目标字符串赋于变量text;并创建了数组groups和locals 。

数组groups是组使用的存储。存储的是当前匹配的各捕获组的first和last信息。

groups[0]存储的是组零的first,groups[1]存储的是组零的last,groups[2]存储的是组1的first,groups[3]存储的是组1的last,依次类推。

Matcher类的方法非常多,这里就不对每个方法的源码进行详细的解读了,后续如果有空会深入研究一下。将常用方法总结如下

方法名 功能作用
public int groupCount() 返回此匹配器中的捕获组数
public String group() 实际上是调用了group(int group) ,只不过参数是0
public String group(int group) 返回当前查找而获得的与组匹配的所有子串内容
public int start() 返回当前匹配的子串的第一个字符在目标字符串中的索引位置
public int start(int group) 返回当前匹配的指定组中的子串的第一个字符在目标字符串中的索引位置 。
public int end() 返回当前匹配的子串的最后一个字符的下一个位置在目标字符串中的索引位置 。
public int end(int group) 返回当前匹配的的指定组中的子串的最后一个字符的下一个位置在目标字符串中的索引位置
public boolean find() 在目标字符串里查找下一个匹配子串
public boolean find(int start) 重置此匹配器,然后尝试查找匹配该模式,从指定的位置开始查找下一个匹配的子串
public int regionStart() 报告此匹配器区域的开始索引。
public int regionEnd() 报告此匹配器区域的结束索引(不包括)。
public Matcher region(int start,int end) 设置此匹配器的区域限制。重置匹配器,然后设置区域,使其从start参数指定的索引开始,到 end参数指定的索引结束(不包括end索引处的字符)。
public boolean lookingAt() 从目标字符串开始位置进行匹配。只有在有匹配且匹配的某一子串中包含目标字符串第一个字符的情况下才会返回true。
public boolean matches() 只有完全匹配时才会返回true。
public Matcher appendReplacement(StringBuffer sb, String replacement) 将当前匹配子串替换为指定字符串,并将从上次匹配结束后到本次匹配结束后之间的字符串添加到一个StringBuffer对象中,最后返回其字符串表示形式。
public StringBuffer appendTail(StringBuffer sb) 将最后一次匹配工作后剩余的字符串添加到一个StringBuffer对象里。
public String replaceAll(String replacement) 将匹配的子串用指定的字符串替换。
public String replaceFirst(String replacement) 将匹配的第一个子串用指定的字符串替换。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • python正则表达式re.search()的基本使用教程

    1 re.search() 的作用: re.search会匹配整个字符串,并返回第一个成功的匹配.如果匹配失败,则返回None 从源码里面可以看到re.search()方法里面有3个参数 pattern: 匹配的规则, string : 要匹配的内容, flags 标志位 这个是可选的,就是可以不写,可以写, 比如要忽略字符的大小写就可以使用标志位 flags 的主要内容如下 flags : 可选,表示匹配模式,比如忽略大小写,多行模式等,具体参数为: re.I 忽略大小写 re.L 表示特殊字

  • Java及python正则表达式详解

    正则表达式语法及常用元字符: 正则表达式有元字符及不同组合来构成,通过巧妙的构造正则表达式可以匹配任意字符串,并完成复杂的字符串处理任务. 常用的元字符有: 其中在使用反斜线时要注意:如果以'\'开头的元字符与转义字符相同,则需要使用'\\'或者原始字符串,在字符串前面加上字符'r'或'R'.原始字符串可以减少用户的输入,主要用于'\\',主要用于正则表达式和文件路径字符串,如果字符串以一个'\'结束,则需要多加一个斜线,以'\\'结束. \  :将下一个字符标记为一个特殊字符.或一个原义字符.

  • Java正则表达式工具方法汇总

    1.获取某字符串中汉字的个数 ... private int getChineseCount(String text) { String Reg = "^[\u4e00-\u9fa5]{1}$";// 正则 int result = 0; for (int i = 0; i < text.length(); i++) { String b = Character.toString(text.charAt(i)); if (b.matches(Reg)) result++; } r

  • 一篇文章带你了解Python和Java的正则表达式对比

    目录 简单批量替换 复杂模板替换 总结 参考资料: 正则表达式语法–菜鸟教程 Java正则表达式实现 简单批量替换 举例:将and 批量替换为&& Python实现 import re def transformSimple(fromRegex, toText, inText): return re.sub(fromRegex, toText,inText, flags =re.I) if __name__ == "__main__": inText = "x

  • Java正则表达式的实例操作指南

    前言 Regular Expression正则表达式,简称RegExp,常规通用的表达式,在多个开发语言中都有它的实现,可以通过正则表达式来快速的检索.匹配.查找.替换字符串中的文本. 简单实例 匹配网址 /* * File:RegExp.java * User:iChochy * URL:https://ichochy.com * Copyright (c) 2020 * Date:2020/09/07 18:11:07 */ package com.ichochy.example; impo

  • Python正则表达式的应用详解

    目录 正则表达式的定义 Python对正则表达式的支持 示例 例1:验证输入的用户名是否有效,用户名由长度为6到20的字母.数字.下划线组成 例2:从字符串中找到与正则表达式匹配的部分 例3:从网页上获取新闻的标题和链接 例4:不良内容过滤 例5:用正则表达式拆分字符串 总结 正则表达式的定义 在编写处理字符串的程时,经常会遇到在一段文本中查找符合某些规则的字符串的需求,正则表达式就是用于描述这些规则的工具,换句话说,我们可以使用正则表达式来定义字符串的匹配模式,即如何检查一个字符串是否有跟某种

  • 超详细讲解python正则表达式

    目录 正则表达式 1.1 正则表达式字符串 1.1.1 元字符 1.1.2 字符转义 1.1.3 开始与结束字符 1.2 字符类 1.2.1 定义字符类 1.2.2 字符串取反 1.2.3 区间 1.2.4 预定义字符类 1.3 量词 1.3.1 量词的使用 1.3.2 贪婪量词和懒惰量词 1.4 分组 1.4.1 分组的使用 1.4.2 分组命名 1.4.3 反向引用分组 1.4.4 非捕获分组 1.5 re模块 1.5.1 search()和match()函数 1.5.2 findall()

  • Java字符串 正则表达式详解

    目录 一.规则表 1.字符 2.字符类 . 3.边界匹配符 4.逻辑操作符 5.量词 二.Pattern类 1.Pattern类的实例获取-compile方法 2.split方法 3.Pattern中匹配标记参数 三.Matcher类 总结 在日常Java后端开发过程中,免不了对数据字段的解析,自然就少不了对字符串的操作,这其中就包含了正则表达式这一块的内容,这里面涉及Java包中Pattern类和Macher类,本篇博客就针对这一块内容和常见的用法进行总结,本博客主要的参考资料是<Java编程

  • Java字符串拼接详解

    目录 一.“+” 操作符 二.StringBuilder(非线程安全) 三.StringBuffer(线程安全) 四.String 类的 concat 方法 五.String 类的 join 方法 六.StringUtils.join 七.不建议在 for 循环中使用 “+” 进行字符串拼接 总结 String类原生的字符串处理方法short s=1;s=s+1;与short s=1;s+=1;的区别 一.“+” 操作符 “+” 操作符是字符串拼接最常用的方法之一.编译的时候会把 “+” 操作符

  • java 中HttpClient传输xml字符串实例详解

    java 中HttpClient传输xml字符串实例详解 介绍:我现在有一个对象page,需要将page对象转换为xml格式并以binary方式传输到服务端 其中涉及到的技术点有: 1.对象转xml流 2.输出流转输入流 3.httpClient发送二进制流数据 POM文件依赖配置 <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifact

  • Java 比较字符串实例详解

     Java 比较字符串实例详解 公司让实现一个自动清除1小时内数据,SQL不熟悉,无奈之下,只能本地DB存储当前时间+小时去和当前时间进行比对.折腾好半天,突然想到Java提供了一个方法,也是进行字符串比较的,傻眼了.一起来看看吧~ CompareTo()方法简介 首先,它属于java.lang.String包下,是Java提供的一个字符串比较的方法,详情介绍如下: CompareTo()返回值: int 返回值类型分别有三种,小于0,等于0,大于0 1. 如果字符串相等返回值0: 2. 如果第

  • java json不生成null或者空字符串属性(详解)

    大家平时用java对象转json字符串.null或者空字符串属性是不需要生成到json字符串里面的. 如下方式生成,没有使用的属性也会生成json字符串属性. JSONArray jsonarray = JSONArray.fromObject(ecmMessageMap.values()); msgObj = jsonarray.toString(); {"actionType":"","clientIp":"","

  • Java String 拼接字符串原理详解

    首先来一道思考题: String str1 = "111111"; String str2 = "222222"; String str = str1 + str2; System.out.println(str); 很明确,上述代码输出的结果是:"111111222222",但是它工作原理是怎样的呢? 由于字符串拼接太常用了,java才支持可以直接用+号对两个字符串进行拼接.**其真正实现的原理是中间通过建立临时的StringBuilder对象

  • Go Java算法之交错字符串示例详解

    目录 交错字符串 方法一:动态规划(Java) 方法一:动态规划(GO) 交错字符串 给定三个字符串 s1.s2.s3,请你帮忙验证 s3 是否是由 s1 和 s2 交错 组成的. 两个字符串 s 和 t 交错 的定义与过程如下,其中每个字符串都会被分割成若干 非空 子字符串: s = s1 + s2 + ... + sn t = t1 + t2 + ... + tm |n - m| <= 1 交错 是 s1 + t1 + s2 + t2 + s3 + t3 + ... 或者 t1 + s1 +

  • Go Java算法之同构字符串示例详解

    目录 同构字符串 方法一:哈希表(Java) 方法一:哈希表(Go) 同构字符串 给定两个字符串 s 和 t ,判断它们是否是同构的. 如果 s 中的字符可以按某种映射关系替换得到 t ,那么这两个字符串是同构的. 每个出现的字符都应当映射到另一个字符,同时不改变字符的顺序.不同字符不能映射到同一个字符上,相同字符只能映射到同一个字符上,字符可以映射到自己本身. 示例 1: 输入:s = "egg", t = "add" 输出:true 示例 2: 输入:s = &

  • Java 常量池详解之字符串常量池实现代码

    目录 1.字符串常量池(String Constant Pool) 1.1:字符串常量池在Java内存区域的哪个位置? 1.2:字符串常量池是什么? 1.3 字符串常量池生成的时机? 如何将String对象放入到常量池 String 对象代码案例解析 new string(“abc”)创建了几个对象 解析public native String intern() 方法 Integer 对象代码案例解析 为啥Integer i1 =10 跟Integer.valueOf(10) 是相等的? 为啥I

  • Javascript类型系统之String字符串类型详解

    javascript没有表示单个字符的字符型,只有字符串String类型,字符型相当于仅包含一个字符的字符串 字符串String是javascript基本数据类型,同时javascript也支持String对象,它是一个原始值的包装对象.在需要时,javascript会自动在原始形式和对象形式之间转换.本文将介绍字符串String原始类型及String包装对象 定义 字符串String类型是由引号括起来的一组由16位Unicode字符组成的字符序列 字符串类型常被用于表示文本数据,此时字符串中的

随机推荐