概述

正则表达式和通配符是两个极易混淆的概念,通常所说的通配符 ( wildcard ) 是指 Bash 操作接口的一个功能,而正则表示法则是一种字符串处理的表示方式。

通配符

从 Spring 路径匹配规则说起

作为一只 Java 程序猿,Spring 是必修课,想必多数人对 Spring 的路径匹配并不陌生,来看一段 SpringMVC 拦截器的配置。

1
2
3
4
5
<!-- 对静态资源文件的访问-->
<mvc:resources mapping="/images/**"  location="/images/"/> 
<mvc:resources mapping="/css/**"  location="/css/" />
<mvc:resources mapping="/js/**/*.js"  location="/js/" /> 

SpringMVC 中的路径匹配要比标准的 web.xml 要灵活的多。默认的策略实现了 org.springframework.util.AntPathMatcher,就像名字提示的那样,路径模式是使用了 Apache Ant 的样式路径,Apache Ant 样式的路径有三种通配符匹配方法:

符号 描述
? 匹配任何单字符
* 匹配 0 或者任意数量的字符
** 匹配 0 或者更多的目录

Ant 风格路径匹配实例

符号 描述
/app/*.x 匹配 ( Matches ) 所有在 app 路径下的 .x 文件
/app/p?ttern 匹配 ( Matches ) /app/pattern 和 /app/pXttern 但是不包括 /app/pttern
/**/example 匹配 ( Matches ) /app/example/app/foo/example, 和 /example
/app/**/dir/file. 匹配 ( Matches ) /app/dir/file.jsp, /app/foo/dir/file.html,/app/foo/bar/dir/file.pdf, 和 /app/dir/file.java
/**/*.jsp 匹配 ( Matches ) 任何的 .jsp 文件

Bash 下的通配符

在 Bash 的操作环境中有一个非常有用的功能,那就是通配符 ( wildcard ) ,我们利用 Bash 处理数据就更方便了,下面我们列出一些常用的通配符:

符号 描述
? 代表 0 个到无穷多个任意字符
. 代表一定有一个任意字符
[] 同样代表一定有一个在括号内的字符(非任意字符)。例如 [abcd] 代表一定有一个字符,可能是 a, b,c, d 这四个任何一个
[ - ] 若有减号在中括号内时,代表在编码顺序内的所有字符。例如 [ 0 - 9 ] 代表 0 到 9 之间的所有数字,因为数字的语系编码是连续的!
[^ ] 若中括号内的第一个字符为指数符号 ( ^ ) ,那表示反向选择,例如 [^abc] 代表一定有一个字符,只要是非 a, b, c 的其他字符就接受的意思。

正则表示法

正则表示法就是处理字符串的方法,他是以行为单位来进行字符串的处理行为,正则表示法通过一些特殊符号的辅助,可以让使用者轻易的达到「搜索/删除/替换」某特定字符串的处理程序!

要使用正则表达式处理文本当然要使用一个支持正则表示法的文本处理程序,如 Notepad++,Vim 编辑器等,本文的示例将采用 Bash 提供的 grep 命令。

符号 描述
^word 意义: 待查找的字符串 ( word ) 在行首。
范例: 查找行首为# 开始的那一行,并列出行号。
命令: grep -n '^#' regular_express.txt
word$ 意义:待查找的字符串 ( word ) 在行。
范例: 将行尾为 ! 的那一行打印出来,并列出行号。
命令: grep -n '!$' regular_express.txt
. 意义: 代表一定有一个任意字符的字符。
范例: 查找的字符串可以是 ( eve ) ( eae ) ( eee ) (e e),但不能仅有 ( ee ) 。即 e 与 e 中间一定仅有一个字符,而空格符也是字符。
命令: grep -n 'e.e' regular_express.txt
\ 意义: 转义字符,将特殊符号的特殊意义去除。
范例: 查找含有单引号 ’ 的那一行。
命令: grep -n \' regular_express.txt
* 意义: 重复零个到无穷多个的前一个 RE 字符
范例: 找出含有 ( es ) ( ess ) ( esss ) 等等的字符串,注意,因为 * 可以是 0 个,所以 es 也是符合待查找字符串。另外,因为 * 为重复前一个 RE 字符的符号,因此,在 * 之前必须要紧接着一个 RE 字符。例如任意字符则为「.*」
命令: grep -n 'ess*' regular_express.txt
[list] 意义: 从字符集合的 RE 字符里面列出想要撷取的字符!
范例: 查找含有 ( gl ) 或 ( gd ) 的那一行,需要特别留意的是,在 [] 当中仅代表一个待查找的字符,例如「 a[afl]y 」代表查找的字符串可以是 aay, afy, aly 即 [ afl ] 代表 a 或 f 或 l 的意思!
命令: grep -n 'g[ld]' regular_express.txt
[n1-n2] 意义: 从字符集合的 RE 字符里面列出想要撷取的字符范围!
范例: 查找含有任意数字的那一行!需特别留意,在字符集合[] 中的减号 - 是有特殊意义的,他代表两个字符之间的所有连续字符!但这个连续与否与 ASCII 编码有关, 例如所有大写字符则为[A-Z]
命令: grep -n '[A-Z]' regular_express.txt
[^list] 意义: 字符集合的 RE 字符,里面列出不要的字符串或范围!
范例: 查找的字符串可以是 ( oog ) ( ood ) 但不能是 (oot) ,那个 ^ 在 [] 内时,代表的意义是反向选择的意思。例如,我不要大写字符,则为 [^A-Z]。但是,如果以 grep -n [^A-Z] regular_express.txt 来查找,却发现该文件内的所有行都被列出,为什么?因为这个[^A-Z] 是非大写字符的意思,因为每一行均有非大写字符。
命令: grep -n 'oo[^t]' regular_express.txt
{n,m} 意义: 连续 n 到 m 个的前一个 RE 字符。
意义: 若为 { n } 则是连续 n 个的前一个 RE 字符
意义: 若是 { n, } 则是连续 n 个以上的前一个 RE 字符!
范例: 在 g 与 g 之间有 2 个到 3 个的 o 存在的字符串,亦即 ( goog ) ( gooog )
命令: grep -n 'go\{2,3\}g' regular_express.txt

小结

正则表示法的特殊字符与一般在指令列输入指令的通配符并不相同,例如,在通配符当中的 * 代表的是「 0 ~ 无限多个字符」的意思,但是在正则表示法当中,* 则是「重复到无穷多个的前一个 RE 字符」的意思。

举例来说,不支持正则表示法的 ls 这个命令中,若我们使用ls -l *代表的是任意名称的文件,而 ls -l a* 代表的是以 a 为开头的任何名称的文件,但在正则表示法中,我们要找到含有以 a 为开头的文件,则必须要这样: ls | grep -n '^a.*'

通过对比 Ant 和 Bash 的通配符可以发现对符号的定义大同小异,Bash 提供的通配符要更多一些,事实上,业界很多优秀的设计思想也是一脉相承的,所谓「一法通则万法通」并不夸张。

[参考]

[1].《鸟哥的 Linux 私房菜》