文章目录
前言
正则表达式是个好东西,可惜我不懂,眼瞎。于是,下决心系统的学习正则表达式,力求看懂正则表达式、会用正则表达式解决日常工作中的问题,提高工作效率。
正则表达式必知必会
入门
匹配任意字符
c.t
-> cat/cut
等
匹配一组字符中的一个
[A-Za-z0-9]
-> 字母和数字
取非操作
[^0-9]
-> 非数字
匹配特殊字符
\d
-> 数字
\D
-> 非数字
\w
-> 字母、数字和_
\s
-> 空白字符(退格[\b]
除外)
切换大小写
\UJava\E
-> JAVA
表示全部大写
\ujava\E
-> Java
表示下一个字符大写
\LJAVA\E
-> java
表示全部小写
\lJAVA\E
-> jAVA
表示写一个字符小写
切换大小写很实用,当我们在使用编辑器时,可以使用(查找的单词)
查找单词,然后\U$1\E
替换为全大写、\u$1\E
替换为首字母大写等等
重复匹配
\d+
-> 1到多个数字
\d*
-> 0到多个数字
\d?
-> 0到1个数字
\d{3,5}
-> 3到5个数字
贪婪匹配和懒惰匹配
*
和+
都是贪婪匹配元字符,举个例子,有这么一段html代码
<h1>你好</h1>
<h1>你们好</h1>
正则表达式为<h1>.*</h1>
,那么它会匹配整个字符串,跟我们的预期有出入,因为贪婪匹配会尽可能的匹配最大的字符串。
改成懒惰匹配可以很好解决这个问题,贪婪匹配元字符加上?
就是懒惰匹配了,本例的正则表达式可以表示为<h1>.*?</h1>
=
位置匹配
\bhelloworld\b
-> helloworld
,helloworldjava
是无法被匹配的
\B-\B
-> -的左右都是非边界字符
^Helloworld
-> 以Helloworld
开始,注意和取非区别,取非运算符写在[]
里面
Helloworld$
-> 以Helloworld
结束
分行匹配模式
如果我们需要匹配换行后的开始和结束字符串,我们可以使用分行匹配模式去改变^
和$
的行为,使用分行匹配模式之后。^
和$
就分别代表换行后的开始边界,换行前的结束边界。举个例子,如果我们需要匹配所有注释,那么可以使用这样的正则表达式(?m)^\s*//.*$
子表达式
为什么出现子表达式?假设我们想匹配多个Helloworld
单词,使用正则表达式Helloworld*
会匹配诸如Helloworlddd
之类的字符串,正确的做法是用小括号将单词包裹起来(Helloworld)*
进阶
回溯引用-前后一致匹配
举个例子,HTML使用h1-h6表示标签,我们现在想匹配所有的标签,可以使用<[hH][1-6]>.*?</[hH][1-6]
,但是如果html表达式里面存在错误的格式,如<h1>标题</h2>
,那么这种方式便行不通。需要用到回溯引用的知识点。
本例使用回溯引用的表达式为<[hH]([1-6])>.*?</[hH]\1>
,其中,\1
表示跟第一个子表达式的匹配一样,如果第一个子表达式匹配2,那么\1
就匹配2
再举一个常用的例子:我现在使用webstorm编辑器,页面上有http://www.baidu.com
的字符串,我想把它替换成<a href="http://www.baidu.com">http://www.baidu.com</a>
,可以使用正则表达式(http:.*)
匹配url,然后使用<a href="$1">$1</a>
替换(webstorm使用$表示匹配的字符串,类似于占位符的作用)。
所以说,正则表达式用好了可以造福人类!
前后查找
向前查找
何谓向前查找,正常情况下,我们需要匹配某个字符,但又不需要在匹配结果中显示它。举个李子:匹配网址的协议,但不需要把:
匹配出来,可以使用\w+(?=:)
而不是\w+:
,因为后者会把:
匹配出来
向后查找
向前查找的对立,比如,要匹配价格的数字,不需要显示$
符号,可以使用(?<=\$).*$
。
双剑合璧
假设我们需要获取<div>Helloworld</div>
里面的内容,可以这样做(?<=<div>).*?(?=</div>)
前后查找的取非
取非的意义是:不匹配向前向后的字符,比如匹配字符串中的数字10$100 can buy 10 apples
,可以这样做\b(?<!\$)\d+\b
放弃
嵌入条件(了解)
嵌入条件比较复杂,了解就好
回溯引用条件
语法:?(子表达式的位置)true_regex|false_regex
我们可能遇到这种情况,假设匹配到左括号,那么我们希望也能够把右括号匹配进去。但是如果没有左括号,我们不希望右括号被匹配到。假设我们希望匹配这两种电话号码
123-456-789
(123)456-789
可以使用(\()?\d{3}(?(1)\)|-)\d{3}-d{3}
前后查找条件
语法:?(前后查找表达式)true_regex
假设我们希望匹配第一行和第三行
11111
22222-
33333-44444
可以使用\d{5}(?(?=-)-\d{5})
Java正则
java正则有一个组的概念,用()括起来,然后可以实现动态替换,比如下面2010-01-01 替换成了01 01
String s = "2010-01-01";
logger.info(s.replaceAll("2010-(\\d\\d)-(\\d\\d)", "$1 $2"))
总结
本篇博客符号较多,可能会产生一些错误,希望各位亲们多多指出!
后记
自从看了《正则表达式必知必会》这本书,发现编辑器的搜索替换功能配合正则表达式简直太强大,可以毫不夸张的说,正则表达式是所有开发人员必备的技能。
参考资料
正则表达式必知必会(修订版) [Ben Forta著]