正则表达式使用规则

1.单个字符的匹配规则如下:

正则表达式 规则 可以匹配
A 指定字符 A
\u548c 指定Unicode字符
. 任意字符 ab&0
\d 数字0~9 0~9
\w 大小写字母,数字和下划线 a`z`,`A`Z0~9_
\s 空格、Tab键 空格,Tab
\D 非数字 aA&_,……
\W 非\w &@,……
\S 非\s aA&_,……

2.多个字符的匹配规则如下

正则表达式 规则 可以匹配
A* 任意个数字符 空,AAAAAA,……
A+ 至少1个字符 AAAAAA,……
A? 0个或1个字符 空,A
A{3} 指定个数字符 AAA
A{2,3} 指定范围个数字符 AAAAA
A{2,} 至少n个字符 AAAAAAAAA,……
A{0,3} 最多n个字符 空,AAAAAA

3.匹配指定范围

比如1A2b3c,我们可以这样写:[0-9a-fA-F],它表示一共可以匹配以下任意范围的字符:
0-9:字符0~9;
a-f:字符a~f;
A-F:字符A~F。

3.1排除法

^ 不包含指定范围的字符

  • 假设我们要匹配任意字符,但不包括数字,可以写[^1-9]{3}

    • 可以匹配"ABC",因为不包含字符1~9

    • 可以匹配"A00",因为不包含字符1~9

    • 不能匹配"A01",因为包含字符1

    • 不能匹配"A05",因为包含字符5

4.或规则匹配

|连接的两个正则规则是规则,例如,AB|CD表示可以匹配ABCD

5.实用括号

现在我们想要匹配字符串learn javalearn phplearn go怎么办?一个最简单的规则是learn\sjava|learn\sphp|learn\sgo,但是这个规则太复杂了,可以把公共部分提出来,然后用(...)把子规则括起来表示成learn\\s(java|php|go)

var 使用括号匹配大写 = "learn\\s([Jj]ava|[Gg]o|[Pp]hp)";
//匹配字符串learn Java、learn Php和learn Go的大小写

6.分组匹配

正则匹配区号-电话号码这个规则

\d{3,4}\-\d{6,8}

如果需要提取区号和电话号码,需要将要提取的规则使用括号分组,把上述正则表达式变为(\d{3,4})\-(\d{6,8})

public class Main {
    public static void main(String[] args) {
        Pattern p = Pattern.compile("(\\d{3,4})\\-(\\d{7,8})");
        Matcher m = p.matcher("010-12345678");
        if (m.matches()) {
            System.out.println(m.group(0));//010-12345678
            String g1 = m.group(1);////010
            String g2 = m.group(2);//12345678
            System.out.println(g1);
            System.out.println(g2);
        } else {
            System.out.println("匹配失败!");
        }
    }
}

使用Matcher时,必须首先调用matches()判断是否匹配成功,匹配成功后,才能调用group()提取子串。

例子:
从字符串23:01:59提取时、分、秒

var time = "([0-1]\\d|2[0-3]):([0-5]\\d):([0-5]\\d)";
Pattern p1 = Pattern.compile(time);
Matcher m1 = p1.matcher("23:01:59");
   if (m1.matches()) {
         System.out.println(m1.group(1));
         System.out.println(m1.group(2));
         System.out.println(m1.group(3));
   } else {
        System.out.println("匹配失败");
   }

7.非贪婪匹配

给定一个字符串表示的数字,判断该数字末尾0的个数。可以很容易地写出该正则表达式:(\d+)(0*)

  • "123000":3个0 期望结果: 123 000 实际结果:"123000" ""

  • "10100":2个0 期望结果: 101 00 实际结果:"10100" ""

  • "1001":0个0 期望结果: 1001 "" 实际结果:"1001" ""

这是因为正则表达式默认使用贪婪匹配:任何一个规则,它总是尽可能多地向后匹配,因此,\d+总是会把后面的0包含进来。

要让\d+尽量少匹配,让0*尽量多匹配,我们就必须让\d+使用非贪婪匹配。在规则\d+后面加个?即可表示非贪婪匹配。

改写正则表达式如下(\d+?)(0*)" 因此,给定一个匹配规则,加上?后就变成了非贪婪匹配。

我们再来看这个正则表达式(\d??)(9*),注意\d?表示匹配0个或1个数字,后面第二个?表示非贪婪匹配,因此,给定字符串"9999",匹配到的两个子串分别是"""9999",因为对于\d?来说,可以匹配1个9,也可以匹配0个9,但是因为后面的?表示非贪婪匹配,它就会尽可能少的匹配,结果是匹配了0个9

8.搜索和替换

8.1 分割字符串

System.out.println(Arrays.toString("a b c".split("\\s")));//[a, b, c]
System.out.println(Arrays.toString("a b  c".split("\\s")));//[a, b, "", c]
System.out.println(Arrays.toString("a,b ;; c".split("[\\,\\s\\;]+")));//[a, b, c]

8.2 搜索字符串

String s = "the quick brown fox jumps over the lazy dog.";
Pattern p3 = Pattern.compile("\\wo\\w");// \w匹配[A-Za-z0-9_]
Matcher m3 = p3.matcher(s);
while (m3.find()) {
   String sub = s.substring(m3.start(), m3.end());
   System.out.println(sub);
   //row fox dog
}

我们获取到Matcher对象后,不需要调用matches()方法(因为匹配整个串肯定返回false),而是反复调用find()方法,在整个串中搜索能匹配上\\wo\\w规则的子串,并打印出来。这种方式比String.indexOf()要灵活得多,因为我们搜索的规则是3个字符:中间必须是o,前后两个必须是字符[A-Za-z0-9_]

8.3 替换字符串

String s2 = "The     quick\t\t brown   fox  jumps   over the  lazy dog.";
String r = s2.replaceAll("\\s+", " ");//将多个空格替换成一个
System.out.println(r); // "The quick brown fox jumps over the lazy dog."

8.4 反向引用

String s3 = "the quick brown fox jumps over the lazy dog.";
String r2 = s3.replaceAll("\\s([a-z]{4})\\s", "<b>$1</b>");
System.out.println(r2);//the quick brown fox jumps<b>over</b>the<b>lazy</b>dog.

它实际上把任何4字符单词的前后用<b>xxxx</b>括起来。实现替换的关键就在于" <b>$1</b> ",它用匹配的分组子串([a-z]{4})替换了$1

8.5 使用Map替换模板中的值

        HashMap<String, String> map = new HashMap<>();
        map.put("name", "Mary");
        map.put("lang", "Java");
        String model = "Hello, ${name}! You are learning ${lang}!";
        Pattern pt = Pattern.compile("\\$\\{([a-z]+)}");
        Matcher mt = pt.matcher(model);
        StringBuilder sb = new StringBuilder();
        while (mt.find()) {
           //0->${name}  1->name
           //0->${lang}  1->lang
           //0 代表整个匹配的字段  1代表匹配字段中的第一个分组
           mt.appendReplacement(sb, map.get(mt.group(1)));
        }
        mt.appendTail(sb);
        System.out.println(sb.toString());
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,123评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,031评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,723评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,357评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,412评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,760评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,904评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,672评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,118评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,456评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,599评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,264评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,857评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,731评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,956评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,286评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,465评论 2 348