正则表达式

Posted Al_tair

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了正则表达式相关的知识,希望对你有一定的参考价值。

正则表达式

正则表达式是对字符串执行模式匹配的技术

底层实现分析

局部匹配

public class RegexpDemo01 
    public static void main(String[] args) 
         String str = "在1958 年,一位名叫Stephen Kleene的数学科学家博尔特," +
                 "1963,他在Warren McCulloch和Walter Pitts早期工作的基础之上,发表了一篇题目是" +
                 "《神经网事件的表示法》的论文,1969利用称之为正则集合的数学符号来描述此模型,引入" +
                 "了正则表达式的概念。1971正则表达式被作为用来描述其称之为“正则集的代数”的一种表达式," +
                 "因而采用了“正则表达式”这个术语。";

         // 匹配正则表达式字符 匹配四个数字
         String regexp = "\\\\d\\\\d\\\\d\\\\d";
         // 生成模式对象
         Pattern pattern = Pattern.compile(regexp);
         // 匹配字符
         Matcher matcher = pattern.matcher(str);
        
        /*
         * matcher.find()
         * 1. 根据 pattern 的规则, 定位满足规则的字符串(比如:1958) 在str的开始索引位置(1)和结束索引位置+1(5)
         * 2. 将索引位置记录到数组groups; 的下标 groups[0] = 0 groups[1] = 4
         * 3. 并且下一次索引开始等于当前的结束索引位置+1 (设置为 5, 表示下一次匹配从5开始)
         * 4. 下次找到数字1963 始索引位置(36)和结束索引位置+1(40)
         * 5. 将索引位置记录到数组groups;的下标groups[0] = 0 groups[1] = 4 记住会覆盖之前的数组下标0,1的数组
         *
         *     特别说明: 当在正则表达式中有()(如(\\\\d\\\\d)(\\\\d\\\\d) ),则表示分组
         *     第1个() 表示第一组  第2个() 表示第2组
         *     2.1 groups[0] groups[1] 记录匹配到的完整结果 如: 1958
         *     2.2 groups[2] groups[3] 记录匹配到的结果的第一个()的内容的开始索引和结束索引+1 即0和2
         *     2.3 groups[4] groups[5] 记录匹配到的结果的第2个()的内容的开始索引和结束索引+1 即2和4
         *
         * ----------------------------------------------------------------------------------------
         *
         * matcher.group(index)
         *     源码分析
         *     public String group(int group) 
         *         if (first < 0)
         *             throw new IllegalStateException("No match found");
         *         if (group < 0 || group > groupCount())
         *             throw new IndexOutOfBoundsException("No group " + group);
         *         if ((groups[group*2] == -1) || (groups[group*2+1] == -1))
         *             return null;
         *         return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
         *     
         * 1. 如果matcher.group(1)从字符串截取下标 groups[0] 到 groups[1]-1 的子字符串
         * 2. 如果matcher.group(1) 截取 groups[2] 到 groups[3] 对应索引的子字符串
         * 2. 如果matcher.group(2) 截取 groups[4] 到 groups[5] 对应索引的子字符串
         *
         * 然后循环的执行find和group的方法
         */
         while(matcher.find()) // 如果查找数组找到的值为-1即没有存入数据则返回false
             System.out.print(matcher.group(0) + "  "); // 1958  1963  1969  1971
         
    

整体匹配

public static void main(String[] args) 
    String str = "12345";
    // 匹配正则表达式字符 匹配四个数字
    String regexp = "\\\\d\\\\d\\\\d\\\\d";
    // 匹配字符 完成匹配
    boolean isMatch = Pattern.matches(pattern,content);
    System.out.println(isMarch); // false

正则表达式语法

元字符

转义符
// 转义符:\\\\ 
public static void main(String[] args) 
    String str = "在1958 年,一位名叫Stephen Kle(ene的(数学科学家博尔特(";
    String regexp = "\\\\("; // ( 会报错
    Pattern pattern = Pattern.compile(regexp);
    Matcher matcher = pattern.matcher(str);
    while (matcher.find())
        System.out.println(matcher.group(0)); // 3个 (
    

限定符

用于指定其前面的字符和组合项连续出现多少次

符号含义示例说明匹配输入
*指定字符重复0次或n次(无要求)零到多(abc)*仅包含任意个abc的字符串,等效于\\w*abc,abcabcabc
+指定字符重复1次或n次(至少一次)m+(abc)*以至少1个m开头,后接任意个abc的字符串m,mabc,mabcabc
指定字符重复0次或1次(最多一次)m+abc?以至少1个m开头,后接ab或abc的字符串mab,mabc,mmmab
n只能输入n个字符[abcd]3由abcd中字母组成的任意长度为3的字符串abc,dbc,adc
n,指定至少n个匹配[abcd]3,由abcd中字母组成的任意长度不小于3的字符串aab,dbc,aaabdc
n,m指定至少n个但不多于m个匹配[abcd]3,5由abcd中字母组成的任意长度不小于3,不大于5的字符串abc,abcd,aaaaaa,bcdab
?匹配模式是"非贪心的"。"非贪心的"模式匹配搜索到的、尽可能短的字符串当此字符紧随任何其他限定符(*、+、?、n、n,、n,m)之后时,

注意:java匹配默认贪婪匹配,即尽可能匹配多的数量 如 a3,4 : aaaa优先级 > aaa优先级

选择匹配符

在选择匹配某个字符串的时候是选择性的( | )

符号含义示例解释
|匹配“|”之前或之后的表达式ab|bcab或者bc
分组组合

常用分组

常用分组构造形式说明
(pattern)非命名捕获。捕获匹配的子字符串。编号为零的第一个捕获是由整个正则表达式模式匹配的文本,其它捕获结果则根据左括号的顺序从1开始自动编号
(?< name >pattern)命名捕获。将匹配的子字符串捕获到一个组名称或编号名称中。用于name的字符串不能包含任何标点符号,并且不能以数字开头。可以使用单引号替代尖括号,例如(?‘name’)
public static void main(String[] args) 
    String str = "在1958 年,一位名叫Stephen Kleene的数学科学家博尔特," +
        "1963,他在Warren McCulloch和Walter Pitts早期工作的基础之上,发表了一篇题目是" +
        "《神经网事件的表示法》的论文,1969利用称之为正则集合的数学符号来描述此模型,引入" +
        "了正则表达式的概念。1971正则表达式被作为用来描述其称之为“正则集的代数”的一种表达式," +
        "因而采用了“正则表达式”这个术语。";

    // 匹配正则表达式字符 匹配四个数字
    // 非命名分组
    String regexp = "(\\\\d\\\\d)(\\\\d\\\\d)";
    // 生成模式对象
    Pattern pattern = Pattern.compile(regexp);
    // 匹配字符
    Matcher matcher = pattern.matcher(str);
    while(matcher.find())
        //  1958  19  58
        //  1963  19  63
        //  1969  19  69
        //  1971  19  71
        System.out.print(matcher.group(0) + "  ");
        System.out.print(matcher.group(1) + "  ");
        System.out.print(matcher.group(2) + "  ");
        System.out.println();
    

    System.out.println("=====================");

    // 命名分组
    regexp = "(?<group1>\\\\d\\\\d)(?<group2>\\\\d\\\\d)";
    pattern = Pattern.compile(regexp);
    // 匹配字符
    matcher = pattern.matcher(str);
    while(matcher.find())
        //  1958  19  58
        //  1963  19  63
        //  1969  19  69
        //  1971  19  71
        System.out.print(matcher.group(0) + "  ");
        System.out.print(matcher.group("group1") + "  ");
        System.out.print(matcher.group("group2") + "  ");
        System.out.println();
    

特别分组

常用分组构造形式说明
(?:pattern)匹配pattern但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于用"o"字符()组合模式部件的情况很有用。例如,'industr(?yies)是比’industryindustries’更经济的表达式
(?=pattern)它是一个非捕获匹配。例如,Windows(?=9598NT2000)'匹配"Windows2000"中的"Vindows",但不匹配"Vindows3.1"中的"Windows"
(?!pattern)该表达式匹配不处于匹配pattern的字符串的起始点的搜索字符串。它是一个非捕获匹配。例如,“Nindows(?!9598NT2000)'匹配"Windows3.1"中的"Windows”,但不匹配"Windows2000"中的"Vindows"
// (?:pattern)
String str = "罗念笙同学和罗念笙父亲以及罗念笙母亲要一起出席会场";
String regexp = "罗念笙(?:同学|父亲|母亲)"; // 等价于 "罗念笙同学 | 罗念笙父亲 | 罗念笙母亲)"
Pattern pattern = Pattern.compile(regexp);
Matcher matcher = pattern.matcher(str);
while(matcher.fins())
    // 不能使用group(1)捕获分组,但是整体是可以用group(0)捕获


// (?=pattern) 和 (?!pattern) 取反关系
字符匹配符
符号含义示例解释
[ ]可接受的字符列表[efgh]e,f,g,h中的任意一个字符
[^]不接收的字符列表[^abc]a,b,c之外的任意一个字符,包括数字和特殊字符
-连字符A-Z任意一个大写字母
.匹配除\\n以外的任何字符a…b以a开头,b结尾,中间包括2个任意字符的长度为4的字符串
\\ \\d匹配单个数字字符,相当于[0-9]\\ \\d3(\\ \\d)?包含3个或4个数字的字符串
\\ \\D匹配单个非数字字符,相当于[ ^ 0-9]]\\ \\D(\\ \\d)*以单个非数字字符开头,后接任意个数字字符串
\\ \\w匹配单个数字、大小写字母字符相当于[0-9a-zA-Z]\\ \\d3\\ \\w4以3个数字字符开头的长度为7的数字字母字符串
\\ \\W匹配单个非数字、大小写字母字符相当于[ ^ 0-9a-zA-Z]\\ \\W+\\ \\d2以至少1个非数字字母字符开头,2个数字字符结尾的字符串
\\ \\ s匹配任何空白字符(空格,制表符等)空格,制表符
\\ \\ S匹配任何非空白字符除空格,制表符之外
// 细节说明
// 不区分大小写
(?!)abc  //  abc都不区分大小写
a(?!)bc  //  abc都不区分大小写
a((?!)b)c // 只有b不区分大小写
Pattern pattern = Pattern.compile(regexp,Pattern.CASE_INSENSITIVE);
定位符

规定要匹配的字符出现的位置

符号含义示例说明匹配输入
^指定起始字符^ [0-9] + [a- z]*以至少1个数字开头,后 串123, 6aa
$指定结束字符^ [0-9]\\ \\ - [a-z] + $以1个数字开头后接连字符“-”,并以至少1个小写字母结尾的字符串1-a
\\ \\ b匹配目标字符串的边界lns\\ \\ b这里说的字符串的边界指的是子串间有空格,或者是目标字符串的结束位置splns,hallns
\\ \\ B匹配目标字符串的非边界lns \\ \\ B和b的含义刚刚相反lnssp,lnsfh

以上是关于正则表达式的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式特殊字符scrapy应用

正则表达式实现计算器

linux 正则表达式基础篇

常用正则表达式总结

正则表达式的符号

正则表达式