常用正则表达式案例

[] 可接受的字符列表,例如[abcd]表示匹配a、b、c、d中任意一字符

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

public class RexDemo {
    public static void main(String[] args) {
        String regExp = "[ab]";
        String content = "apple and book";
        Pattern pattern = Pattern.compile(regExp);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println(matcher.group(0));
        }

    }
}

输出

a
a
b

[^] 不可接受的字符列表 [^abc] 除a,b,c之外的任意一个字符,包括数字和特殊符号;
[^a-z]表示不匹配a-z中的任意一个字符;
[^0-9]表示不匹配0至9中任意一个字符;

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

public class RexDemo {
    public static void main(String[] args) {
        String regExp = "[^ab]";
        String content = "a & b";
        Pattern pattern = Pattern.compile(regExp);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println(matcher.group(0));
        }
    }
}

输出(注意空格符也被匹配上了):

' '
&
' '

[^a-z]{2} {2}表示连续2个字符不是a-z的字符,如A111匹配结果11

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

public class RexDemo {
    public static void main(String[] args) {
        String regExp = "[^a-z]{2}";
        String content = "a000b";
        Pattern pattern = Pattern.compile(regExp);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println(matcher.group(0));
        }
    }
}

输出(匹配的是b前面的两个00):

00
符号 -  符号 - 连字符 A-Z 任意单个大写字母
符号. 匹配除\n以外的任何字符 a..b表示以a开头,以b结尾,中间包括2个任意字符长度为4的字符串,如aaab,aefb,a35b,a*&b
\\d 匹配单个数字字符,相当于[0-9]
\\d{3} 等价与\\d\\d\\d
\\d{3}(\\d)? 包含3个或4个数字的字符串,如123,8765等
\\D 匹配单个非数字字符,相当于[^0-9] 
\\D(\\d)* 表示以单个非数字字符开头,后接任意个数字字符串,如f、d1234等
\\w 匹配单个数字,大小写字母,下划线,相当于[0-9a-zA-Z_]
\\d{3}\\w{4} 表示以3个数字字符开头的长度为7的字符串
\\W 匹配单个非数字、大消息字母字符,相当于[^0-9a-zA-Z_]
\\W+\\d{2} 表示匹配至少一个非数字,非字母字符开头,2个数字字符结尾的字符串 如#26,#?@67
选择匹配符号| ,表示匹配"|"之前或之后的表达式,如 ab|cd 表示匹配ab或者cd
符号* 表示指定字符重复0次或者n次,如(abc)* ,仅包含任意个abc的字符串,等效与\W*,匹配abc、abcabcabc
符号+ 表示指定字符重复1次或n次(至少一次),m+(abc)*,以至少1个m开头,后接任意个abc的字符串,m,mabc,mabcabc
(?i)abc 表示不区分大小写,匹配abc、Abc等
a(?i)bc或者a(?i)(bc) 表示bc不区分大消息
也可以手动指定不区分大小写
Pattern pattern = Pattern.compile(regStr, Pattern.CASE_INSENSITIVE);
\\s 匹配任何空白字符(空格,制表符等)
\\S 匹配任何非空白字符,和\s刚好相反
.匹配出\n之外的所有字符,如果要匹配.本身,则需要使用\\.

限定符 *+?{}

* 指定的字符重复0次或n次,即0到多;如(abc)匹配abc,abcabc等
+ 指定字符重复1次或n次,如a+(bcd)*匹配至少1个a开头,任一个bcd结尾的字符,如a,abcd,abcdbcd等
?指定字符重复0或1次,如a+bc?表示至少一个a开头,b或者bc结尾的字符串,如ab或者abc,aabc等
{n}只能输入n个字符,如[abcd]{3},表示由a,b,c,d中字母组成的任意长度为3的字符串,如abc,acd,adc等
{n,}至少n次匹配,[abcd]{3,}表示由abcd中字母组成的任意长度不小于3的字符串,如abc,aab等
{n,m}指定至少n个但不多余m个匹配,[abcd]{3,5}表示由abcd中字母组成的任意长度在3到5之间的字符串,如abc,adddd等;

定位符"^" "$" "\b" "\B"

^指定起始字符,如^[0-9]+[a-z]*表示至少一个数字开头,任意个小写字母结尾的字符串,如9a,8等;
$指定结束字符,^[0-9]\\-[a-z]$表示以一个数字开头,后接-,并以a到z任意一个字母结尾
^[0-9]\\-[a-z]+$表示以一个数字开头,后接-,并以a到z任意一个或多个字母结尾
\\b 匹配目标字符串的边界,边界指存在空格或者结尾,如aa\\b匹配kkkaa,kkaa,kk aa等
\\B匹配目标字符串的非边界,边界指开头或者空格,如aa\\B,匹配aadkkklll,aa88,aa uu等

分组

1.非命名捕获

(pattern) 非命名捕获,捕获匹配的字符串,编号为0的第一个捕获是由整个正则表达式模式匹配的文本,其他捕获结果则根据左括号的顺序从1开始自动编号

代码实例

        String content = "huawei nanjing2022 hua0318sheng";
        String regExp = "(\\d\\d)(\\d\\d)";
        Pattern pattern = Pattern.compile(regExp);
        Matcher matcher = pattern.matcher(content);

        while (matcher.find()) {
            System.out.println(matcher.group(0));
            System.out.println(matcher.group(1));
            System.out.println(matcher.group(2));
            System.out.println("------");
        }

输出

2022
20
22
------
0318
03
18
------

2.命名捕获

(?<name>pattern)命名捕获,将匹配的子字符串捕获到一个组名称或编号名称中,用于name的字符串不能包含任何标点符号,并且不能以数字开头,可以使用单引号替代尖括号,如(?'name')

代码实例

        String content = "huawei nanjing2022 hua0318sheng";
        String regExp = "(?<group1>\\d\\d)(?<group2>\\d\\d)";
        Pattern pattern = Pattern.compile(regExp);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println(matcher.group(0));
            System.out.println(matcher.group(1));
            System.out.println(matcher.group(2));
            System.out.println(matcher.group("group1"));
            System.out.println(matcher.group("group2"));
            System.out.println("------");
        }

输出

2022
20
22
20
22
------
0318
03
18
03
18
------

3.非捕获匹配(?:pattern)

表示匹配pattern,但不捕获匹配的子表达式,对于用or字符"|"组合模式部件的情况很有用,例如huaweinanjing|huaweishenzhen 比huawei(?:nanjing|shenzhen)要繁琐

代码实例

//        String regExp = "huaweinanjing|huaweishenzhen|huaweihangzhou";
        String regExp = "huawei(?:nanjing|shenzhen|hangzhou)";
        String content = "hello huaweinanjing huaweishenzhen huaweihangzhou";
        Pattern pattern = Pattern.compile(regExp);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println(matcher.group(0));
        }

运行结果

huaweinanjing
huaweishenzhen
huaweihangzhou

4.非捕获匹配(?=pattern)

(?=pattern)限定了捕获的范围,如tigger(?=3|5|7)匹配tigger3中的tigger,不匹配tigger2中的tigger

代码实例

        String regExp = "tigger(?=3|5|7)";
        String content = "tigger2 tigger3 tigger5";

        Pattern pattern = Pattern.compile(regExp);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println(matcher.group(0));
        }

输出

tigger // tigger3中的tigger
tigger // tigger5中的tigger

5.非捕获匹配(?!pattern)

该表达式匹配不处于匹配pattern的字符串的起始点的搜索字符串,如tigger(?!3|5|7)不匹配tigger3中tigger,不匹配tigger5中的tigger,不匹配tigger7中的tigger,但可以匹配tigger2中的tigger

代码实例

        String regExp = "tigger(?!3|5|7)";
        String content = "tigger2 tigger3 tigger5";

        Pattern pattern = Pattern.compile(regExp);
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println(matcher.group(0));
        }

输出

tigger // tigger2中的tigger

元字符说明

^、$、?(默认非贪婪,如\\d+改成非贪婪匹配\\d+?只匹配一个)

常用场景

1.校验字符串是否是汉字

        // 校验字符串是否是汉字
        String content = "华为";
        String regExp = "^[\u0391-\uffe5]+$";
        Pattern pattern = Pattern.compile(regExp);
        Matcher matcher = pattern.matcher(content);
        if (matcher.find()) {
            System.out.println("是汉字");
        } else {
            System.out.println("不全部是汉字");
        }

2.校验字符串是否是邮政编码

        // 校验字符串是否是邮政编码
        String content = "236566";
        // 1-9开头,紧接着是5位数字结尾
        String regExp = "^[1-9]\\d{5}$";
        Pattern pattern = Pattern.compile(regExp);
        Matcher matcher = pattern.matcher(content);
        if (matcher.find()) {
            System.out.println("是");
        } else {
            System.out.println("否");
        }

3.校验字符串是否是QQ号码

        // 校验字符串是否是QQ号码
        String content = "383754990";
        // 1-9开头,总长度在5到10位的数字
        String regExp = "^[1-9]\\d{4,9}$";
        Pattern pattern = Pattern.compile(regExp);
        Matcher matcher = pattern.matcher(content);
        if (matcher.find()) {
            System.out.println("是");
        } else {
            System.out.println("否");
        }

4.校验字符串是否是手机号码

        // 校验字符串是否是手机号码
        String content = "15276876755";
        // 13,14,15,18开头的11位数字
        String regExp = "^1[3|4|5|8]\\d{9}$";
        Pattern pattern = Pattern.compile(regExp);
        Matcher matcher = pattern.matcher(content);
        if (matcher.find()) {
            System.out.println("是");
        } else {
            System.out.println("否");
        }

5.校验字符串是否是URL

        String content = "https://www.bilibili.com/video/BV11A41157Sa?spm_id_from=333.999.0.0";
        // 1. ^((http|https)://) 匹配https://
        // 2. ([\w-]+\.)+[\w-]+ 匹配www.bilibili.com
        // 3. (/[\w-?=&/%.#]*)? 匹配 /video/BV11A41157Sa?spm_id_from=333.999.0.0
        // [\w-?=&/%.]匹配?,=,&,/,%,.等
        // [.]等价于//. 匹配.本身
        // . 匹配除\n之外的所有字符
        String regExp = "^((http|https)://)?([\\w-]+\\.)+[\\w-]+(\\/[\\w-?=&/%.#]*)?$";
        Pattern pattern = Pattern.compile(regExp);
        Matcher matcher = pattern.matcher(content);
        if (matcher.find()) {
            System.out.println("是");
        } else {
            System.out.println("否");
        }

整体匹配

        String content = "hello nanjing";
        // String regExp  = "hello"; // false
        String regExp  = "hello.* "; // true .*代表任意个字符
        // 整体匹配
        boolean matches = Pattern.matches(regExp, content);
        System.out.println(matches);
注意事项:整体匹配Pattern.matches()与matcher.find()存在一定区别,前者是整体匹配,后者是局部匹配,正则表达式上存在一些区别,不能混用。

整体匹配与局部匹配区别的代码实例

        String content = "hello nanjing";
        String regExp = "hello"; // false
        // String regExp = "hello.* "; // true .*代表任意个字符
        // 整体匹配
        boolean matches = Pattern.matches(regExp, content);
        System.out.println(matches);
        System.out.println("---------------");

        Pattern pattern = Pattern.compile(regExp);
        Matcher matcher = pattern.matcher(regExp);
        if (matcher.find()) {
            System.out.println("存在匹配的串");
        } else {
            System.out.println("不存在匹配的串");
        }

输出:

false
---------------
存在匹配的串

分组、反向引用、捕获

分组:用圆括号组成一个比较复杂的匹配模式,这个圆括号的部分可以看作是一个子表达式,也即一个分组

反向引用:圆括号的内容被捕获后,可以在这个括号后被使用,从而写出一个比较实用的匹配模式,这个我们称为反向引用,这种引用既可以是在正则表达式的内部,也可以是在正则表达式的外部,内部反向引用\分组号,外部反向引用$分组号

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

分组,反向引用,捕获的代码实例

String regExp = "(\\d)\\1";  // 表示连续两位相同的数字,匹配如11、44、55等

String regExp = "(\\d)(\\d)\\2\\1"; // 表示连续的四位数字,1与4位相同,2与3位相同,匹配如1221、3223等

String regExp = "\\d{5}-(\\d)\\1{2}(\\d)\\2{2}(\\d)\\3{2}"; // 匹配连续5位的数字,后面连-,后面连续9位数字,其中每连续3位是相同的情况,如22221-777888999等

口吃去重实例:要求去掉一句话中连续重复的冗余字符,只保留一个即可,如"我....我是中..中.国南南南京人",需要去掉“.”以及连续出现的字符,最终变成“我是中国南京人”

String content = "我....我是中..中.国南南南京人";

// 1.先去掉所有的.
String dotRegExp = "\\.";

Pattern pattern = Pattern.compile(dotRegExp);
Matcher matcher = pattern.matcher(content);
content = matcher.replaceAll("");
// 2.去掉连续重复的字符,只保留一个
// "(.)\\1+"表示匹配任意多个连续字符
// "$1"外部引用,使用第一个字符替换连续重复的字符
Pattern.compile("(.)\\1+").matcher((content)).replaceAll("$1");

String类中使用正则表达式

校验手机号是否138或者139开头,且长度11位

        String content = "13887667805";
        String regExp = "13(?:8|9)\\d{8}";
        if (content.matches(regExp)) {
            System.out.println("合法");
        } else {
            System.out.println("非法");
        }

替换字符串中特定字符串

        // 使用南京替换nanjing
        String content = "nanjing1 是一座美丽的城市,nanjing2拥有悠久的历史,丰厚的文化底蕴...";
        content = content.replaceAll("nanjing(?:1|2)", "南京");
        System.out.println(content);

指定分割符分割字符串

        // 分隔符为+、=、*、-等符号
        String content = "hell-o+nanjing=yuhua+998*77777";
        String[] array = content.split("\\*|-|=|\\+");
        for (String arr : array) {
            System.out.println(arr);
        }

常用场景

验证邮箱合法性

        // .在中[]中表示.本身
        // ^[\w-]+ 表示字符开头,长度1到N位
        // @ 表示@本身
        // ([a-zA-Z0-9]+\\.)+ 表示1到N组"字母数字."的组合,如cn.;com.;edu.cn.等
        // [a-zA-Z0-9]+ 表示字母数字组合长度1到N位不等
        String regExp = "^[\\w-]+@([a-zA-Z0-9]+\\.)+[a-zA-Z0-9]+";
        String content = "mac2099@163.com";
        System.out.println(content.matches(regExp));

解析URL

注意:下面的代码逻辑只具有一定的参考性,具体解析规则要根据实际要求来定

        String content = "https://www.bilibili.com/video/BV11A41157Sa?spm_id_from=333.999.0.0&name=zhangsan";
        // 采用分组方式处理
        String regExp = "([a-zA-Z]+)://([\\w-.]+)(:\\d+|)([/\\w-]*)([?]*)([[\\w_.]*=[\\w_.]*&*]+)";

        Pattern pattern = Pattern.compile(regExp);
        Matcher matcher = pattern.matcher(content);

        while (matcher.find()) {
            System.out.println(matcher.group(0));
            // 协议
            System.out.println(matcher.group(1));
            // 域名
            System.out.println(matcher.group(2));
            // 路径
            System.out.println(matcher.group(4));
            // 参数列表
            System.out.println(matcher.group(6));
        }

常用正则表达式参考

数字 :^[0-9]*$
n位的数字:^\d{n}$
至少n位的数字:^\d{n,}$
m-n位的数字:^\d{m,n}$
零或者非零开头的 数字:^(0|[1-9][1-9]*)$
非零开头的最多带两位小数的数字:^([1-9][0-9*])+(.[0-9]{1-2})?$
带1-2位小数的正数或负数:^(\-)?\d+(\.\d{1,2})?$
正数、负数和小数:^(\-|\+)?\d+(\.\d+)?$
两位小数的正数:^[0-9]+(.[0-9]{2})?$
有1-3位小数的正数:^[0-9]+(.[0-9]{1,3})?$
非零的正整数:^[1-9][0-9]*$或^[1-9]\d*$等
非零的负整数:^-[1-9]\\d*$
非负整数:^\\d+$或者^[1-9]\\d*|0$
非正整数:^-[1-9]\\d*|0$或者^((-\\d+)|(0+))$
非负浮点数:^\\d+(\\.\\d+)?$
非正浮点数:^((-\\d+(\\.\\d+)?)|(0+(\\.0+)?))$
正浮点数:^[1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*$
负浮点数:^-([1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*$
浮点数:^(-?\\d+)(\\.\\d+)?$

校验字符表达式
汉字:^[\u4e00-\u9fa5]+$
英文和数字:^[A-Za-z0-9]+$
长度为3-20的所有字符:^.{3,20}$
中文,英文,数字包括下划线:^[\u4e00-\u9fa5A-Za-z0-9_]+$
可以输入含有^T%,;=?$\等字符:[^T%,;=?$\x22]+
禁止输入含有~的字符[^~\x22]+
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容

  • 正则表达式(Java版整理) 基础 元字符 重复 字符类 想查找数字,字母或数字,空白是很简单的,因为已经有了对应...
    NowBurn阅读 1,038评论 0 1
  • 元字符 代码说明.匹配除换行符以外的任意字符\w匹配字母或数字或下划线或汉字\s匹配任意的空白符\d匹配数字^匹配...
    Mr_Fly阅读 623评论 0 0
  • 最近学习到第 23 天了,还有 4 天时间我的 JavaSE 课程就要结束了,之后会有一个考试,需要复习一下,正好...
    SawyerZh阅读 1,043评论 0 11
  • 前段时间做聊天消息的解析,涉及到要在群消息中查找@的人,需要把@后面的用户昵称解析出来,首先想到的当然就是用正则来...
    waiwaaa阅读 1,131评论 0 2
  • 第一次认真的写一次博客,虽然很多都是copy ,但把这些整理和总结出来,一边理解,自己也熟悉不少。本篇寄语:在生活...
    L63C阅读 506评论 0 2