正则学习二三事

正则一直是我一大痛点,一直都想解决这个问题,但是奈何每次看到那么多符号就发蒙,所以就一直拖下去了。直到最近总是被别人问到如何在hql中使用rlike查询符合特定规则的字段,然后各种不会,结果被鄙视的一塌糊涂,无奈,这才静下心来慢慢研究。
以前看正则就是一堆符号,代表各个意思,如\d表示数字,\d+表示一个或者多个连续数字,单看每个规则都可以理解,除了组合,但是实际使用时真的很难组织到一起。归根结底还是因为对这些符号的理解不够深入。所以正则还是得多写,推荐一个在线练习的网站RegexGolf。好了,下面写写自己学习正则的一些总结吧,希望能够帮助到别人,也帮助自己总结总结。

正则的基础知识:

  • 字面值
    正则表达式由只代表自身的字面值和代表特定含义的元字符组成。 只代表自身的字面值指的是普通的字符,如abcde,特殊含义的元字符包括

    字符 含义
    \ 反斜线字符
    \0n 带有八进制值 0 的字符 n (0 <= n <= 7)
    \0nn 带有八进制值 0 的字符 nn (0 <= n <= 7)
    \0mnn 带有八进制值 0 的字符 mnn(0 <= m <= 3、0 <= n <= 7)
    \xhh 带有十六进制值 0x 的字符 hh
    \uhhhh 带有十六进制值 0x 的字符 hhhh
    \t 制表符 (‘\u0009’)
    \n 新行(换行)符 (‘\u000A’)
    \r 回车符 (‘\u000D’)
    \f 换页符 (‘\u000C’)
    \a 报警 (bell) 符 (‘\u0007’)
    \e 转义符 (‘\u001B’)
    \cx 对应于 x 的控制符
  • 字符类
    字符类是字符在方括号中的集合。表示“找到集合里任意一个字符“。例如:

    字符 含义
    [abc] a、b 或 c(简单类)
    [^abc] 任何字符,除了 a、b 或 c(否定)
    [a-zA-Z] a 到 z 或 A 到 Z,两头的字母包括在内(范围)
    [a-d[m-p]] a 到 d 或 m 到 p:[a-dm-p](并集)
    [a-z&&[def]] d、e 或 f(交集)
    [a-z&&[^bc]] a 到 z,除了 b 和 c:[ad-z](减去)
    [a-z&&[^m-p]] a 到 z,而非 m 到 p:[a-lq-z](减去)

    从上表可以看出[]里面可进行并集/交集/差集操作。对于字符范围是根据ASCII值的大小来的,例如[A-z]也是可以的,甚至能够匹配[,但是完全不建议如此使用,推荐使用的字符范围:[0-9]/[a-z]/[A-Z]。
    字符类还有一些预定义的字符类:

    字符 含义
    . 任何字符(与行结束符可能匹配也可能不匹配)
    \d 数字:[0-9]
    \D 非数字: [^0-9]
    \s 空白字符:[ \t\n\x0B\f\r]
    \S 非空白字符:[^\s]
    \w 单词字符:[a-zA-Z_0-9]
    \W 非单词字符:[^\w]

    使用上面的预定义字符类能够更加方便的表示字符范围。需要牢记。
    注意: 区间是字符的区间,不是数字的区间。正则表达式[1-31]表示“找到一个1或一个2或一个3”,不是“找到一个从1到31的整数”。

  • 乘法器

    字符 含义
    X? X,一次或一次也没有
    X* X,零次或多次
    X+ X,一次或多次
    X{n} X,恰好 n 次
    X{n,} X,至少 n 次
    X{n,m} X,至少 n 次,但是不超过 m 次

    X可以使一个普通字面值,如a+:一个或多个a,也可以是一个字符类,如[abc]{2},表示a/b/c后跟a/b/c。
    值得注意的是优先选择更长的匹配,因为乘法器是贪婪的。如果你输入的文本是I had an aaaaawful day,该正则表达式就会在aaaaawful中匹配到aaaaa。不会在第三个a后就停止匹配。
    乘法器是贪婪的,但它不会忽略一个更好的匹配。如果你的输入文本为I had an aaawful daaaaay,之后这个正则表达式会在第一次的匹配中于aaawful找到aaa。只有在你说“给我找到另一个匹配”的时候,它才会继续搜索然后在daaaaay中找到aaaaa。
    惰性:
    正则表达式“.表示“找到一个双引号,接着找到尽可能多的字符,最后再找到一个双引号”。注意一下被.匹配的内部字符,很可能包含多个双引号。这通常不是非常有用。乘法器可通过追加问号(?)来实现惰性“.?”*表示“匹配一个双引号,跟着一个尽可能少的字符,再跟着一个双引号”。

  • 分支
    可以使用管道符号来实现匹配多种选择。

    字符 含义
    X|Y X或者Y
  • 组合
    可以使用圆括号来组合表达式。例:
    在一周中找到一天,使用(Mon|Tues|Wednes|Thurs|Fri|Satur|Sun)day,这里如果把小括号或者中括号,结果是完全不一样的,因为中括号是字符类,即里面的Mon并不是完全匹配Mon,而是只要匹配M/o/n其中一个即可。
    同时组合后面还可跟上乘法器,如:\w+(\s+\w+)*代表“找到一个或多个单词,它们以空格隔开”。

  • 边界
    边界分成:单词边界,行边界,文本边界

    1. 单词边界
      单词边界是一个单词字符和非单词字符之间的位置。记住,一个单词字符是\w,它是[0-9A-Za-z_],一个非单词字符是\W,也就是[^0-9A-Za-z_]。
      文本的开头和结尾总是当作单词边界。
      输入的文本it’s a cat有八个单词边界,分别为:文本开头-i,t-‘,’-s,s-空格,空格-a,a-空格,空格-c,t-文本结尾。
    2. 行边界
      每一块文本会分解成一个或多个行,用换行符分隔。
      注意文本不是以换行符结束,而是以行结束。然而,任何行,包括最后一行,可以包含零个字符。
      起始行位置是在一个换行符和下一行的第一个字符之间。与单词边界一样,在文本的开头也算作一个起始的行。结束行位置是在行的最后一个字符和换行符之间。与单词边界一样,文本结束也算作行结束。
    3. 文本边界
      很多实现提供一个标记,通过改变它来改变^和$的含义。从“行开始”和“行结束”变成“文本开始”和“文本结束”。其它的一些实现提供单独的元字符\A和\z来达到这个目的。

    一些表示边界的符号:

    字符 含义
    ^ 行的开头
    $ 行的结尾
    \b 单词边界
    \B 非单词边界
    \A 输入的开头
    \G 一个匹配的结尾
    \Z 输入的结尾,仅用于最后的结束符(如果有的话)
    \z 输入的结尾

    其中^$是最常用的两个边界分隔符。

捕获和替换:

  1. 捕获组
    ()在正则中被用来表示组,同时也可以用来捕获匹配上的子串,可以拥有多个捕获组,它们甚至可以嵌套使用,捕获组从左到右进行编号,只要计算左圆括号。例如:
    对于表达式:(\w+) had a ((\w+) \w+),文本是I had a nice day,那么

    • 捕获组1是I。
    • 捕获组2是nice day。
    • 捕获组3是nice。
    • 捕获组0是I had a nice day(根据具体实现不同)

    如果表达式使用了两个捕获组,但是只捕获到一组,那么组2是空字符串。引用捕获组使用+组序号,如\1表示引用第一个捕获组。

  2. 后向引用
    可以在同样的表达式中引用同一个捕获组,这称为后向引用。
    例:表达式[abc]{2}表示“匹配aa或ab或ac or ba或bb或bc或ca或cb或cc”,但是表达式([abc])\1表示“匹配aa或bb或cc”。

以上就是正则的全部知识,其实了解正则的知识点很简单,但是真要应用到实际中还是需要通过大量的练习才能做到熟练使用。

实际案例
  1. 压缩CSS文件,去掉CSS文件中的换行以及空格
工具:Notepad++  查找:([{;])\s+  替换:\1

以上案例会不断更新,已记录一些自己对正则使用的经历。

参考文章

55分钟学会正则表达式(译) JDK api文档

相关文章

正则替换html代码中img标签的src值在开发富文本信息在移动端...
正则表达式
AWK是一种处理文本文件的语言,是一个强大的文件分析工具。它...
正则表达式是特殊的字符序列,利用事先定义好的特定字符以及...
Python界一名小学生,热心分享编程学习。
收集整理每周优质开发者内容,包括、、等方面。每周五定期发...