这两篇教程写的不错,可以入门参考
入门请参考:https://juejin.im/post/5b96a8e2e51d450e6a2de115
入门后可参考:https://juejin.im/post/5b6adc7ee51d4534b8587560
我以前没写过博文,我尝试去写一篇,发现真的还是比较困难的,不在于具体知识有多难,而是真的写不出来文字来,请多多包涵。所以我先只写一些正则表达式的例子,供大家赏玩。
所有的正则表达式都是在Sublime Text 3中执行测试通过的。Sublime Text 3有列选中和列编辑的功能,用起来非常非常爽,在Windows系统下可以使用Notepad++来代替。
例1
我从linux中的某个目录下使用ls -l命令,得到以下内容,现在我要保留最后一列,如何处理?
剖析:观察所有字符串,发现每一行都是由9部分组成,每部分之间由空格隔开,空格数量不一样(从选中情况来看,每个点代表一个空格,第一行和其它行略有不同),我们从最简单开始,先给第二行到最后一行的这些字符串定做一个**模板**:
-
每一行由9部分组成,那就分9组(9个圆括号):
()()()()()()()()()
-
每个部分之间把空格加上,原来每部分之间有几个空格,就加几个:
() () () () () () () () ()
在正则表达式中,空格可以用
\s
来表示,\s
表示很多空格,比如空白格,换行符,制表符等看不见的空格\s
都可以表示,具体去查查基础资料。 -
接下来分析每部分都是由什么组成的:
- 第一部分(drwxr-xr-x):由若干个任意字符组成,至少有一个:
.+
(解释一下:.
表示任意字符,+
表示至少有一个,也可以写成.*
,表示任意字符,有任意多个,可以是0
个) - 第二部分(9):由若干个字符组成,至少有一个:
.+
- 第三部分(liyanlong):由若干个任意字符组成,有任意多个:
.*
- 第三部分(liyanlong): 你也可以说是由任意字符组成,至少有一个:
.+
- 第三部分(liyanlong): 你可以说就是由
liyanlong
组成:liyanlong
- 从第四部分开始,我就不写了,你认为模板是什么,就是什么,只要能解释的通,都是对的,所以正则表达式比较灵活,没有标准答案,目的不是追求唯一和完美,而是条条大路通罗马,一百个人有一百个正则表达式,但是最终效果却都是相同的,这不是很好吗
所以以下都正确:
- 第一部分(drwxr-xr-x):由若干个任意字符组成,至少有一个:
(.*) (.*) (.*) (.*) (.*) (.+) (.+) (.+) (.*)
复制代码
(.*) (.*) (liyanlong) (staff) (.*) (.+) (.+) (.+) (.*)
复制代码
\d
表示一个数字, 我把所有数字替换成\d
, 既然我们是写字符串模板,所以要考虑模板如何才能匹配到现有的字符
(.*) (.*) (liyanlong) (staff) (\d\d\d) (\d) (\d\d) (\d\d:\d\d) (.*)
复制代码
\d{n:m}
表示最少n
个数字,最多m
个数字,\d{m}
表示只有m
个数字,等价于\d{m,m}
(.*) (.*) (liyanlong) (staff) (\d{3}) (\d{1,1}) (\d{2,2}) (\d{2}:\d{2}) (.*)
复制代码
\d
表示数字,[0-9]
也表示数字,可以相互替换
(.*) (.*) (liyanlong) (staff) ([0-9]{3}) ([0-9]{1,1}) (\d{2,2}) ([0-9]{2}:\d{2}) (.*)
复制代码
好了,我就不继续写了,总之,你只要认为你的模板能匹配到截图中的字符串,那么你的模板就是对的,你写的正则表达式就是合格的,然后测试一下即可。
...
复制代码
-
那就还剩下最后一步,就是替换,保留最后一列
最开始咱么说了,每个字符分
9
组,从第一左括号开始,分别用$1、$2、$3、$4...
表示第一组,第二组,第三组,第四组...$0
表示全部字符串,$9
表示第9
组,截图中的正则表达式表示“选中”字符串,然后用Replace框中的正则表达式去替换。最后效果就是,留下第一行伫立在风中,你就动动手自己解决吧,只剩下最后一行了,还要什么自行车!!!
例2
对下图中的身份证号进行脱敏(身份证号都是我随机生成的数组序列而已,勿怪)
剖析:怎么处理呢?首先要做一个字符串模板,能够匹配所有字符串,然后跟例1中的类似,找个$n来替换一下就可以了。那我们来尝试写个 模板:
我们将字符串分为四组,即前4位,中间10位,后面再来3位,最后1位
-
先将身份证号分为四组:
()()()()
-
明细:
- 第一组(前4位):
\d\d\d\d
、\d{4}
、[0-9]{4}
都可以 - 第二组(中间10位): 跟第一组类似,推荐用
\d{10}
- 第三组(接下来的3位):同理:
\d{3}
- 第四组(最后一位):可能是数字,也可能是
X
:\d|X
(|表示或)
- 第一组(前4位):
-
按最优方式最终组成:
(\d{4})(\d{10})(\d{3})(\d|X) 使用 $1****$3$4 替换
复制代码
同理,我们也可以将字符串分为三组:前面4位,中间10位,最后面4位
(\d{4})(\d{10})(\d{3}(\d|X)) 使用 $1****$3 来替换
复制代码
非常简单有好使,不信你自己试试,骗你是小狗。最终效果就是这样的:
问题: 在(\d{4})(\d{10})(\d{3}(\d|X))
中,如果我写成(\d{4})(\d{10})(\d{3}\d|X)
,也就是最后一组中,没有加小括号,那么正则表达式认为\d{3}\d
是一伙的,X
是一伙的,所以必须是嵌套一个小括号,明明白白告诉正则表达式解析器,\d{3}
是独立存在的。
另外:如果我替换时,将$1****$3
写成了$3****$1
会出现啥情况?自己试试看,看看惊不惊喜,意不意外!!!
例3
给一个sample.html页面,然后找出所有的a
标签中的链接值,即所有的href
属性值。
剖析: 我是这么处理的:我首先通过java读取文件的方式,逐行读取文本,然后通过正则表达式匹配到a
标签所在行,舍弃所有其它行。然后从正则表达式中提取href
属性值。那么做这一切的关键点就是如何通过正则表大会匹配正确的文本行了。
那么正则表达式是个字符串模板,那我该怎么写这个模板呢,以<a href='/commands/append'>
为例,我是这么思考的:
以
<a
开头,然后是一个空格,然后有个href属性,属性值可以为任意字符串,属性值包含在''
中,然后以一个换行符结尾。我们写一个试试:
<a href='.+'>\n # \n表示换行符
复制代码
我试了一下,哎呦喂,完全可以啊,但是美中不足的一点是,我需要通过\n
来匹配字符,但是我不需要这个\n
, 用术语来说就是零宽度正预测先行断言
, 匹配\n
的这部分属于非捕获组
。我们先写完,然后再解析。
<a href='(.+)'>(?=\n)
复制代码
呵,完美啊,简直没毛病,可以了。下面可以不看了,直接去看例4吧。
**结语: **对于什么是捕获组
,非捕获组
, 还有零宽断言
之类的,我希望这里抛出来,你如果不会,就要去自己找资料,掘金里有好多写得非常优秀的博文,你去翻一翻,基本都是免费的。如果你用心了,还学不会,可以找我来讨论。
好了,我们在看一个不是那么完美的正则表达式,
画外音:我就是喜欢这种缺陷美
(<a)( )(href=.*?)(?=\n)
复制代码
分析: 这是三个括号,我们能看懂吧,分别就是第一组,第二组,第三组,第四组
- 第一组匹配
<a
, 表示以字符串<a
开始 - 第二组匹配一个空格
- 第三组匹配一个以
href=
开始的字符,后面可以跟任意多个任意字符。 等等.*
表示匹配任意多个任意字符,最后的这个问号是个什么鬼? 最后的这个问号表示非贪婪
匹配,也就是尽可能少的去匹配。举个例子:上面这个正则表达式可以匹配<a href=renyizifu\n
, 也可以匹配<a href=renyizifu\n任意字符\n
, 那默认是要匹配第二个的,也就是贪婪匹配,最大匹配,但是加上问号,就表示非贪婪匹配,也就是最小匹配。 - 第四组是一个
正向零宽断言
,正向
就是往前,就是紧接着,也就是字符串右边,零宽
就是中间啥也不隔着,也就是紧接着,断言
就是预测的意思。最后一组表达的意思就是:前三组匹配之后,紧接着要匹配一个叫做\n
的字符串,\n
就是换行符,别找了,肉眼是看不见滴。而且,这个断言
的内容是非捕获的,也就是说,我要找的字符串啊,最后是以\n
结尾的,但是\n
又不属于我这个字符串的范围内的,你只管匹配就好,我不需要对你做任何操作,所以我的正则表达式模板要操作的字符串中没有非捕获的内容。