java学习笔记 正则

https://www.runoob.com/regexp/regexp-metachar.html*

java.util.regex 包主要包括以下三个类:

  • Pattern 类:
    pattern 对象是一个正则表达式的编译表示。Pattern 类没有公共构造方法。要创建一个 Pattern 对象,你必须首先调用其公共静态编译方法,它返回一个 Pattern 对象。该方法接受一个正则表达式作为它的第一个参数。

  • Matcher 类:
    Matcher 对象是对输入字符串进行解释和匹配操作的引擎。与Pattern 类一样,Matcher 也没有公共构造方法。你需要调用 Pattern 对象的 matcher 方法来获得一个 Matcher 对象。


    image.png

    image.png
  • PatternSyntaxException:
    PatternSyntaxException 是一个非强制异常类,它表示一个正则表达式模式中的语法错误。

  1. 限定符
  2. 选择匹配符
  3. 分组组合和反射引用符
    分组我们可以用圆括号组成一个比较复杂的匹配模式,那么一个圆括号 的部分我们可以看作是一个子表达式/一个分组
    反射引用,圆括号 的内容被捕获后,可以在这个括号 后被使用,从而写出一个比较实用的匹配模式,这个我们称为反向引用,这种引用既可以是在正则表达 式内部,也可以是在正则表达式外部,内部反向引用\分组号,外部反向引用$分组号
# 要匹配两个连续的相同的数字
(\\d)\\1
# 要匹配五个连接相同的数字
(\\d)\\1{4}
# 要匹配个位与千位相同,十位与百位相同的数字
(\\d)(\\d)\\2\\1
# 12321-333999111,要求满足前面是一个五位数,然后“-”,然后是九位数,连续的每三位要相同
String str = "12321-333999111";
String reg2 = "\\d{5}-(\\d)\\1{2}(\\d)\\2{2}(\\d)\\3{2}";

捕获,把正则表达式中子表达式/分组匹配的内容,保存到内存中以数字编号或显式命名的组里,方便后面引用,从左向右,以分组的左括号 为标志,第一个出现的分组的组号为1,第二个为2,以此类推,组0代表的是整个正则式。

  1. 特殊字符
  2. 字符匹配符
  3. 定位符




根据 Java Language Specification 的要求,Java 源代码的字符串中的反斜线被解释为 Unicode 转义或其他字符转义。因此必须在字符串字面值中使用两个反斜线,表示正则表达式受到保护,不被 Java 字节码编译器解释。例如,当解释为正则表达式时,字符串字面值 "\b" 与单个退格字符匹配,而 "\b" 与单词边界匹配。字符串字面值 "(hello)" 是非法的,将导致编译时错误;要与字符串 (hello) 匹配,必须使用字符串字面值 "\(hello\)"。

  • 元字符-转义号\\
    在Java中的正则表达式中,两个\ 代表其它语言中的一个
    .*+()$/\?[]{}^这些都需要转义。

  • 元字符-字符匹配符

  • 元字符-选择匹配符
    在匹配某个字符串的时候是选择性的,即:既可以匹配这个,又可以匹配那个,这时你需要用到选择匹配符 |

  • 元字符-定位符
    定位符,规定要匹配的字符串出现的位置,比如在字符串的开始还是在结束的位置,这个也是相当有用的。^$ \\b \\B

  • 分组

    • (?<name>pattern) 命名捕获。将匹配的子字符串捕获到一个组名称或编号名称中。用于name的字符串不能包含任何标点符号,并且不能以数字开头。可以使用单引号替代尖括号。如:(?'name')
    • (pattern) 非命名捕获。捕获匹配的子字符串,编号为零的第一个捕获是由整个正则表达式模式匹配的文本,其它捕获结果则根据左括号的顺序从1开始自动编号
    • (?:pattern) 匹配pattern 但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于“or”字符(|)组合模式部件的情况 很有用。indeustr(?:y|ies)industry|industries更方便
    • (?=pattern) 它是一个非捕获匹配。例如Windows (?=95|98|NT|2000)匹配“Windows 2000”中的“Windows”,但不匹配“Windows 3.1”中的“Windows”
    • (?!pattern) 执行反向预测先行搜索的子表达式,该表达式匹配不处于匹配 pattern 的字符串的起始点的搜索字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,Windows (?!95|98|NT|2000) 匹配Windows 3.1中的 Windows,但不匹配Windows 2000中的Windows。预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。
  • 结巴


# d{3}代表3个数字, ()? 代表括号里的可能出现0次或1次,所以这个意思是包含3个或4个数字的字符串。
\\d{3}(\\d)?
# *号表示0次或任意多次,以单个非数字字符开头,后接任意个数的字符串
\\D(\\d)*
# 以3个数字开头,后接任意4个数字或大小写字符。
\\d{3}\\w{4}
# +号表示至少出现一次或多次,以至少1个非数字字母开头,后接两个数字字符结尾
\\W+\\d{2}
# (?i)后面的不区分大小写,
# abc不区分大小写
(?i)abc
# bc不区分大小写
a(?i)bc
# b不区分大小写
a((?i)b)c
# CASE_INSENSITIVE字符不敏感
Pattern pat = Pattern.compile(regEx, Pattern.CASE_INSENSITIVE)

# \\s 匹配任何空白字符  \\S匹配任何非空白字符
#任意多个abc的字符串abc,abcabc,abcabcabc
(abc)*
#以一个或多个m开头,接多个abc的字符串,mabc,mmabc,mabcabc,mmabcabc等
m+(abc)*
# 以至少1个m开关,接ab,接0个或1个c. mab,mabc,mmab,mmabc,这个问号还能切换成非贪心模式。
m+abc?
# abcd中任意组合的3位字符,abc,dbc,adc等
[abcd]{3}
# abcd中组合出至少3位的字符。
[abcd]{3,}
# abcd中组合出3-5位字符。
[abcd]{3,5}
# 以1位或多位数字开头,接多个小写字母。^这个东西在[]中就是反向字符集,非质就是以什么开头
^[0-9]+[a-z]*
# 以一个数字开头,接‘-’连接符,接至少1个小写字母结尾,1-a,1-aa
^[0-9]\\-[a-z]+$
# 这里说的字符串的边界指的是子串间有空格,或者是目标字符串的结束位置,相当于匹配ee,但在结尾, 在空格、逗号、句号等前面是断位,一般不是数字、字母、下划线都能断开。
ee\\b
和\\b相反,匹配ee,但不出现在结尾
ee\\B

# 非命名捕获。捕获匹配的子字符串,编号为零的第一个捕获是由整个正则表达式模式匹配的文本,其它捕获结果则根据左括号的顺序从1开始自动编号
(pattern)
String str = "1234"
(//d//d)(//d//d)
group(0)=1234  group(1)=12 group(2)=34
(//d//d)(//d)(//d)
group(0)=1234  group(1)=12 group(2)=3 group(3)=4
# 命名捕获。将匹配的子字符串捕获到一个组名称或编号名称中。用于name的字符串不能包含任何标点符号,并且不能以数字开头。可以使用单引号替代尖括号。如:`(?'name')`
(?<name>pattern)
String str = "1234"
(?<g1>//d//d)(?<g2>//d//d)
group("g1")=12 group("g2")=34

# `(?:pattern)`,`(?=pattern)`,`(?!pattern)`
indeustr(?:y|ies) =》indeustry indeustries
Windows (?=95|98|NT|2000) =》Windows
public class regex01 {
    public static void main(String[] args) {
        String content="在最近的六十年中,正则表达式逐渐从模糊而深奥的数学概念,发展成为在计算机各类工具" +
                "和软件包应用中的主要功能。不仅仅众多UNIX工具支持正则表达式,近二十年来,在WINDOWS的阵" +
                "营下,正则表达式的思想和应用在大部分 Windows 开发者工具包中得到支持和嵌入应用!从正" +
                "则表达式在Microsoft Visual Basic 6 或 Microsoft VBScript到.NET Framework" +
                "中的探索和发展,WINDOWS系列产品对正则表达式的支持发展到无与伦比的高度,几乎所有 " +
                "Microsoft 开发者和所有.NET语言都可以使用正则表达式。如果你是一位接触计算机语言" +
                "的工作者,那么你会在主流操作系统(*nix[Linux, Unix等]、Windows、HP、BeOS等)、" +
                "主流的开发语言" +
                "(delphi、Scala、PHP、C#、Java、C++、Objective-c、Swift、VB、Javascript、Ruby以及Python等)、" +
                "数以亿万计的各种应用软件中,都可以看到正则表达式优美的舞姿。";

        // 1. 创建Pattern对象
//        String regex="[a-zA-Z]+";
//        String regex="[0-9]+";
//        String regex="([a-zA-Z]+)|([0-9]+)";
        String regex="([a-zA-Z]+)|([0-9]+)";
        Pattern pattern = Pattern.compile(regex);
        // 2. 创建一个匹配器对象,就是matcher匹配器,按pattern(样式),到content文本中,
        Matcher english = pattern.matcher(content);
        // 3. 开始循环。
        while (english.find()){
            // 匹配内容放到matcher.group(0)
            System.out.println("find:"+english.group(0));
        }

        System.out.println("==============");
    }
    @Test
    public void fourNum(){
        String strYear ="1998年12月8日,第二代Java平台的企业版J2EE发布。" +
                "1999年6月,Sun公司发布了第二代Java平台(简称为Java2)的3个版本。Java 2平台的1221发布,标志着Java的应用开4664始普及。";
        // 1. 找字4个数字连在一起的子串
        // 2. 找出4个数字连在一起的子串,且1、4位相同,2、3、位相同
        // 匹配4个数字
        // \d任意一个数字,\\d\\d\\d\\d表示四个连在一起的数字
        String regStr ="\\d\\d\\d\\d";
        Pattern compile = Pattern.compile(regStr);
        Matcher matcher = compile.matcher(strYear);
        while (matcher.find()){
            // groups[group*2],groups[group*2+1],即当group=0时,groups[0]=0,group[1]=4就是【0-4)包含0
            // 不包含4。
            System.out.println(matcher.group(0));
        }
    }
    // 包含括号里的东西
    @Test
    public void reg03(){
        String str="indeustry indeustries";
        String reg="indeustr(?:y|ies)";
        Pattern compile = Pattern.compile(reg);
        Matcher matcher = compile.matcher(str);
        while (matcher.find()){
            System.out.println(matcher.group(0));
        }
    }
    
    // 不包含括号里的东西
    @Test
    public void reg04(){
        String str="Windows 95,Windows 98,Windows 2000,Windows NT,Windows 3.1";
        String reg="Windows (?=95|98|NT|2000)";
        Pattern compile = Pattern.compile(reg);
        Matcher matcher = compile.matcher(str);
        while (matcher.find()){
            System.out.println(matcher.group(0));
        }
    }
    // 相当于上面的取反
    @Test
    public void reg05(){
        String str="Windows 95,Windows 98,Windows 2000,Windows NT,Windows 3.1";
        String reg="Windows (?!95|98|NT|2000)";
        Pattern compile = Pattern.compile(reg);
        Matcher matcher = compile.matcher(str);
        while (matcher.find()){
            System.out.println(matcher.group(0));
        }
    }
}

问号作用

  • 零次或一次匹配前面的字符或子表达式。例如,"do(es)?"匹配"do"或"does"中的"do"。? 等效于 {0,1}。
  • 当此字符紧随任何其他限定符(*、+、?、{n}、{n,}、{n,m})之后时,匹配模式是"非贪心的"。"非贪心的"模式匹配搜索到的、尽可能短的字符串,而默认的"贪心的"模式匹配搜索到的、尽可能长的字符串。例如,在字符串"oooo"中,"o+?"只匹配单个"o",而"o+"匹配所有"o"。


    image.png

首位记录的是当前字符索引值,尾位是记录当前字符索引值+1,方便继续下次开始读的位置。分组后,首先是匹配一个大组,连续四个数字,战胜了group[0],group[1],然后记录组1的开始与结尾使用group[2],group[3],组2,再记录组2的开始与结尾使用group[4],group[5]。

贪心与非贪心

  • “非贪心的”模式匹配搜索到的,尽可能短的字符串,
  • 默认的“贪心的”模式匹配搜索的,尽可能长的字符串。
    换句话说,本身*、+、?、{n}、{n,}、{n,m}这些字符就是可以匹配0个至多个,非贪心就是尽可能少,贪心就是尽可能多。

应用

一、校验数字的表达式
1. 数字:^[0-9]*
2. n位的数字:^\d{n}
3. 至少n位的数字:^\d{n,}
4. m-n位的数字:^\d{m,n}
5. 零和非零开头的数字:^(0|[1-9][0-9]*)$  ^//d+
6. 非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?
7. 带1-2位小数的正数或负数:^(\-)?\d+(\.\d{1,2})?
8. 正数、负数、和小数:^(\-|\+)?\d+(\.\d+)?
9. 有两位小数的正实数:^[0-9]+(.[0-9]{2})?
10. 有1~3位小数的正实数:^[0-9]+(.[0-9]{1,3})?
11. 非零的正整数:^[1-9]\d* 或 ^([1-9][0-9]*){1,3} 或 ^\+?[1-9][0-9]*
12. 非零的负整数:^\-[1-9][]0-9"* 或 ^-[1-9]\d*
13. 非负整数:^\d+ 或 ^[1-9]\d*|0
14. 非正整数:^-[1-9]\d*|0 或 ^((-\d+)|(0+))
15. 非负浮点数:^\d+(\.\d+)? 或 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0
16. 非正浮点数:^((-\d+(\.\d+)?)|(0+(\.0+)?)) 或 ^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0
17. 正浮点数:^[1-9]\d*\.\d*|0\.\d*[1-9]\d* 或 ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))
18. 负浮点数:^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*) 或 ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))
19. 浮点数:^(-?\d+)(\.\d+)? 或 ^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)

二、校验字符的表达式
1. 汉字:^[\u4e00-\u9fa5]{0,}
2. 英文和数字:^[A-Za-z0-9]+ 或 ^[A-Za-z0-9]{4,40}
3. 长度为3-20的所有字符:^.{3,20}
4. 由26个英文字母组成的字符串:^[A-Za-z]+
5. 由26个大写英文字母组成的字符串:^[A-Z]+
6. 由26个小写英文字母组成的字符串:^[a-z]+
7. 由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+
8. 由数字、26个英文字母或者下划线组成的字符串:^\w+ 
9. 中文、英文、数字包括下划线:^[\u4E00-\u9FA5A-Za-z0-9_]+$
10. 中文、英文、数字但不包括下划线等符号:^[\u4E00-\u9FA5A-Za-z0-9]+$或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}
11. 可以输入含有^%&',;=?$\"等字符:[^%&',;=?$\x22]+ 12 禁止输入含有~的字符:[^~\x22]+
 
三、特殊需求表达式
 1. Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
2. 域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
3. InternetURL:[a-zA-z]+://[^\s]* 或 ^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$
4. 手机号码:^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$
5. 电话号码("XXX-XXXXXXX"、"XXXX-XXXXXXXX"、"XXX-XXXXXXX"、"XXX-XXXXXXXX"、"XXXXXXX"和"XXXXXXXX):^(\(\d{3,4}-)|\d{3.4}-)?\d{7,8}$
6. 国内电话号码(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}
7. 身份证号(15位、18位数字):^\d{15}|\d{18}$
8. 短身份证号码(数字、字母x结尾):^([0-9]){7,18}(x|X)?$ 或 ^\d{8,18}|[0-9x]{8,18}|[0-9X]{8,18}?$
9. 帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
10. 密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$
11. 强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
12. 日期格式:^\d{4}-\d{1,2}-\d{1,2} 这个不对 没考虑月份与大小月。
13. 一年的12个月(01~09和1~12):^(0?[1-9]|1[0-2])$
14. 一个月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$
16. 有四种钱的表示形式我们可以接受:"10000.00" 和 "10,000.00", 和没有 "分" 的 "10000" 和 "10,000":^[1-9][0-9]*$
17. 2.这表示任意一个不以0开头的数字,但是,这也意味着一个字符"0"不通过,所以我们采用下面的形式:^(0|[1-9][0-9]*)$
18. 一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号:^(0|-?[1-9][0-9]*)$
19. 这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧.下面我们要加的是说明可能的小数部分:^[0-9]+(.[0-9]+)?$
20. 5.必须说明的是,小数点后面至少应该有1位数,所以"10."是不通过的,但是 "10" 和 "10.2" 是通过的:^[0-9]+(.[0-9]{2})?$
21. 这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:^[0-9]+(.[0-9]{1,2})?$
22. 这样就允许用户只写一位小数.下面我们该考虑数字中的逗号了,我们可以这样:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$
23. 到3个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$
24. 备注:这就是最终结果了,别忘了"+"可以用"*"替代如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里
25. xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$
27. 双字节字符:[^\x00-\xff] (包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))
28. 空白行的正则表达式:\n\s*\r (可以用来删除空白行)
29. HTML标记的正则表达式:<(\S*?)[^>]*>.*?</\1>|<.*? /> (网上流传的版本太糟糕,上面这个也仅仅能部分,对于复杂的嵌套标记依旧无能为力)
30. 首尾空白字符的正则表达式:^\s*|\s*$或(^\s*)|(\s*$) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)
31. 腾讯QQ号:[1-9][0-9]{4,} (腾讯QQ号从10000开始)
32. 中国邮政编码:[1-9]\d{5}(?!\d) (中国邮政编码为6位数字)
33. IP地址:\d+\.\d+\.\d+\.\d+ (提取IP地址时有用)
34. IP地址:((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))

再来些例子

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容