正则表达式可以让处理文本的速率咻咻的往上提高,以前不会玩正则的时候,在对一段文本内容的提取时,那真的是,用火箭炮打毛毛虫的感觉,码半天,还不一定高效,虽然能得出结果,但是,完全没有编码体验,对自己的感觉,就是菜,举个不成熟的例子:“小明约小红,2018-06-07去湖南路88-2号去玩。”需求说,我就要这段文字的2018-06-07 或者就要2018和06-07,再举个日期的例子:比如用户录入信息,每个人提交自己的生日,最后汇聚起来,有的人写了19900101,有的人写的1990-01-01,有的写的1990/01/01,有的写的1990*01*01,好,需要把这些全部过滤提取起来。
以上都是对于文本的内容的提取和过滤,我所举的案例,如果使用正则的方式去实现的话,都是极其简单的
我们先理解正则中的一些元素,说话先会说词,明白每个元素的意思,再连接在一起就简单多了,正则语言,比英语可简单多了
元字符
^行的开始 ^cat 用来匹配文本在这一行的开头
行的结束cat 行 的 结 束 c a t 只寻找定位于行末的cat
字符组([ ])
[……]匹配若干字符之一,使用者列出在某处期望匹配的字符,通常被称作字符组
例如gr[ea]y 的意思是,先找到g,跟着一个r,然后一个a或者e,最后一个是y。在普通字符’g’ ‘r’部分是先匹配g再匹配r ,但是在[ ]中是匹配e或者a,并不存在顺序上的关联,[ea]的意思也是只匹配r之后一个字符是a或者是e,不在匹配字符组字符之后的其他字符
如H[1234567890],只匹配H1,H2,H3,H4,H5,H6,H7等 且等同于H[0-9]
也可以实现多重范围写作[ 0- 9a- fA- F]
只有在字符组内部,连字符(-)才是元字符–否则它就只能匹配普通的连字字符,如果连字符出现在字符组的开头(即紧跟[或者[^)它就表示的就是一个普通的字符,而不是一个范围,问号和点号通常被当作元字符处理,但在字符组中则不是如此,就是普通的字符。
[^……] 在这个字符组中^是除……之外的意思,比如[^1-6]处1到6的数字之外的其他任何字符,在字符组外部它表示一个锚点,即行的开始
排除型字符组表示’匹配一个未列出的字符’而不是‘不要匹配列出的字符’
用点号匹配单个任意字符 元字符 (.)
在[ ]中点号并不是元字符只是普通字符
多选结构(|)
|是一个非常简捷的元字符,它的意思是or(或),通过它我们能将一个子表达式组成一个总表达式,而这个总的表达式又能匹配任意的子表达式。[jack|lisa]就是技能匹配jack又能匹配lisa
回头 来看「 gr[ ea] y」 的 例子, 有意思 的 是, 它 还可以 写作「 grey| gray」, 或者是「 gr( a| e) y」。 后者 用 括号 来 划定 多 选 结构 的 范围( 正常 情况下, 括号 也是 元 字符)。 请注意,「 gr[ a| e] y」 不符合 我们 的 要求—— 在这里,‘|’ 只是 一个 和「 a」 与「 e」 一样 的 普通 字符。
多选字符|的括号()是必须的,因为如果没有括号,「 gra| ey」 的 意思 就成 了“「 gra」 或者「 ey」” 括号是控制范围
一个字符组只能匹配目标文本中的单个字符,而每个多结构自身都可能是完整的正则表达式,可以匹配任意长度
字符 组 基本 可以 算是 一门 独立 的 微型 语言( 例如, 对于 元 字符, 它们 有 自己的 规定), 而 多 选 结构 是“ 正 则 表达式 语言 主体( main regular expression language)” 的 一部分。 你将 会 发现, 这 两者都 非常 有用。
可选项字符(?)
「u?」 这个 元 字符 与我 们 之前 看到 的 元 字符 都不 相同, 它 只作 用于 之前 紧邻 的 元素。 因此,「 colou? r」 的 意思是:「 c」, 然后 是「 o」, 然后 是「 l」, 然后 是「 o」, 然后 是「 u?」, 最后 是「 r」。
「u?」 是 必然 能够 匹配 成功 的, 有时 它 会 匹配 一个 u, 其他 时候 则 不匹配 任何 字符。
所以可以算一个量词,有或无
重复出现(+和*)
+表示与之前紧邻的元素出现一次或者多次
*表示与之前紧邻的元素出现任意多次或者不出现
就是,「…*」 表示“ 匹配 尽可能 多的 次数, 如果 实在 无法 匹配, 也不 要紧”。「…+」 的 意思 与之 类似, 也是 匹配 尽可能 多的 次数, 但 如果 连 一次 匹配 都无 法 完成, 就 报告 失败。 问号、 加号 和 星号 这 3 个 元 字符, 统称 为 量词( quantifiers), 因为 它们 限定 了 所作 用 元素 的 匹配 次数。
?和*号是永远不会匹配失败的
规定重现次数的范围:区间({})
区间:「…{ min, max}」。 这 称为“ 区间 量词( interval quantifier)”。 例如,「…{ 3, 12}」 能够 容许 的 重现 次数 在 3 到 12 之间。 有人 可能 会用「[ a- zA- Z]{ 1, 5}」 来 匹配 美国 的 股票 代码( 1 到 5 个 字母)。 问号 对应 的 区间 量词 是{ 0, 1}。
括号 及 反向 引用()
主要的功能是限制多选项的范围
其他还有很多其他的一些表达式语法,但是基础常用的就是这些,一般就是元字符,字符组,点,多选分支,量词,区间,括号,这样就几乎写出几千万化的正则表达式了。
要想解决我们开始抛出的问题,还需要了解一个很重要的概念,叫做捕获组。
捕获组
捕获组是把多个字符当一个单独单元进行处理的方法,它通过对括号内的字符分组来创建。
例如,正则表达式 (dog) 创建了单一分组,组里包含”d”,”o”,和”g”。
捕获组是通过从左至右计算其开括号来编号。例如,在表达式((A)(B(C))),有四个这样的组:
((A)(B(C)))
(A)
(B(C))
(C)
可以通过调用 matcher 对象的 groupCount 方法来查看表达式有多少个分组。groupCount 方法返回一个 int 值,表示matcher对象当前有多个捕获组。
还有一个特殊的组(group(0)),它总是代表整个表达式。该组不包括在 groupCount 的返回值中。
简单说,就是通过括号,可以捕获到我们想要的数据
让我们再回到开始的问题,第一个问题是在一段文字中扣出我们要的日期数据,就可以写成(\d{4})-(\d{2}-\d{2}),如此一来,第一个括号就补货到了年份这个数据,后面的括号就补货到了月份和日期的数据,2018和06-07,非常好用,再看第二个问题,各种日期格式获取这个问题依然非常简单,如果我们不用正则的话,本身逻辑也不复杂,多个if语句判断即可,但是万一多加了一个特殊分隔符的话就必须多加一个判断分支,想想就很麻烦,用正则就很简单,还是\d{4}(.?)\d{2}(.?)\d{2},就是这么简单,点可以匹配任意字符,?是可有可无,这样它只会匹配任意年月份特殊分割的字符,代码处理极其简洁。
我写的正则都是极其简单的,但掌握这些算是能够应对一般的文本问题了。