什么是正则表达式?
讲真"正则"这个词真的挺抽象,汉语里应该没有这个组合,不知道为什么这样翻译,倒是对应的英文更好理解一些。正则表达式( Regular Expression, RE )是处理字符串的方法,通过一些特殊字符的排列(或者说是模式模板),以行为单位,可以实现查找、删除、替换某特定字符串的功能。好像还是有些不明白,按我的理解来说,正则表达式就像是一张网,用来捕鱼的网,正则表达式中的特殊字符组合就相当于网眼的大小。通过调整字符组合就可以调整网眼尺寸,从而实现捕捉想要捕捉尺寸的鱼,同理,通过正则表达式就可以实现对数据的筛选分流,快速筛选出目标文本(字符,or anything you want)。
为什么要学正则表达式
上篇介绍了两个文本编辑器sed和gawk,在处理文本时用到的命令(模式)就是正则表达式,正则表达式有多丰富,两款工具的功能就有多强大。正则表达式种类很多,其实现需要正则表达式引擎( regular expression engine ),正则表达式引擎是一套底层软件,负责解释正则表达式模式并使用这些模式进行文本匹配。Linux中有两种主流正则表达式引擎:
- 基础正则表达式( basic regular expression, BRE)引擎
- 扩展正则表达式( exended regular expression, ERE)引擎
基础正则表达式( BRE )
1. 纯文本
最最基本的BRE模式就是匹配数据流中的文本字符。这部分上篇已经讲过,话不多说,直接看示例:
# sed示例
$ echo "This is a test" | sed -n '/test/p'
This is a test
$
# gawk示例
$ echo "This is a test" | gawk '/test/{print $0}'
This is a test
$
# 需要注意的
正则表达式匹配模式很挑剔,所以匹配的时候会区分大小写;
在正则表达式中,无需写出整个单词,只要定义的文本出现在数据流中,正则表达式就能匹配;
正则表达式中,空格和其他字符并无区别;
2. 锚字符
锁定在行首:脱字符( ^ ) 锁定在行尾:美元符( $ )
比较简单,不多说,看示例就能懂:
# 行首(必须是精确匹配)
$ echo "This is a test" | sed -n '/^This/p'
This is a test
$
# 行尾(必须是精确匹配)
$ echo "This is a test" | sed -n '/test$/p'
This is a test
$
3. 点号字符
点号字符( . )属于特殊字符,用来匹配除换行符之外的任意单个字符(必须匹配一个字符,否则模式就不成立)。
还是举例说话:
# 一行一行地看匹配模式
$ cat test.txt
This is a beautiful world.
The cat is sleeping.
That is a very nice hat.
This test is at line four.
at ten o`clock we`ll go home.
$
$ sed -n '/.at/p' test.txt
The cat is sleeping.
That is a very nice hat.
This test is at line four.
$
4. 字符组
如果想要限定待匹配的字符的具体值,点号字符就力不从心了。这个时候需要字符组( character class ), 字符组可以用方括号( [ ] )定义,可在其中写入想要的字符。看示例:
# 这是个极简单的例子,用法其实还有很多,比如连用几个字符组,区间字符(数字)等~
$ sed -n '/[ch]at/p' test.txt
The cat is sleeping.
That is a very nice hat.
$
5. 排除性字符组
顾名思义,跟字符组是相反的,没错,用的特殊字符就是脱字符^,简单到不想多说。
6. 区间
可以说是字符组的一个延伸,比如设置数字匹配模式时,如果想匹配0到9之间的任意数字,可以用下面的方式:
# 常规的字符组表示法
[0123456789]
# 区间表示法,简单很多,起始中间用 "-"
[0-9]
# 以此类推,字母也一样的,比如a-z,A-Z
[a-z], [A-Z]
# 具体用法参照上面字符组即可
7. 特殊字符组
看名称就知道,也是字符组,也算是普通字符组的延伸,不多说,直接摘抄如下:
[[:alpha:]] 匹配任意字母字符,不区分大小写
[[:alnum:]] 匹配任意字母数字字符0-9,a-z,A-Z
[[:blank:]] 匹配空格或制表符
[[:digit:]] 匹配0-9之间的数字
[[:lower:]] 匹配小写字母字符a-z
[[:print:]] 匹配任意可打印字符
[[:punct:]] 匹配标点符号
[[:space:]] 匹配任意空白字符:空格、制表符、NL、FF、VT和CR
[[:upper:]] 匹配任意大写字母字符A-Z
# 同样的,用法参照普通字符组
7. 星号
这里的星号()和Linux命令中的通配符不一样,在正则表达式中,字符后面放置星号表明该字符必须在匹配模式的文本中出现0次或多次*。看示例体会一下:
# 认真体会下最后一个
$ echo "bt" | sed -n '/b[ae]*t/p'
bt
$ echo "bat" | sed -n '/b[ae]*t/p'
bat
$ echo "bet" | sed -n '/b[ae]*t/p'
bet
$ echo "btt" | sed -n '/b[ae]*t/p'
btt
扩展正则表达式( ERE )
正则表达式模式中使用文本字符时,对于一些特殊字符需要格外注意,因为一些字符在正则表达式中是有特别含义的,包括:
. * [] ^ $ {} \ + ? | ()
其中一些字符在基础正则表达式中已经介绍,那扩展正则表达式又扩展在哪里呢?主要是几个只能够被gawk识别,但是sed却无法识别的字符:? + {} | ()
1. 问号
问号与星号作用类似,区别在于问号表明前面的字符可以出现0次或1次(没有其他值)。看示例理解:
# 需要理解所谓的精确匹配,以及方括号的含义
$ echo "bt" | gawk '/b[ae]?t/{print $0}'
bt
$ echo "bat" | gawk '/b[ae]?t/{print $0}'
bat
$ echo "bot" | gawk '/b[ae]?t/{print $0}'
$
$ echo "bet" | gawk '/b[ae]?t/{print $0}'
bet
$ echo "baet" | gawk '/b[ae]?t/{print $0}'
$
$ echo "beat" | gawk '/b[ae]?t/{print $0}'
$
$ echo "beet" | gawk '/b[ae]?t/{print $0}'
$
2. 加号
同于与星号功能类似,同样也有细微区别。加号表示前面字符可以出现1次或多次,且必须至少出现1次。不想举例了~
3. 花括号
跟方括号可以限定具体的匹配字符一样,花括号可以实现正则表达式中对某个模式具体重复次数的限定,有两种形式:
- m:正则表达式准确出现几次
- m,n: 正则表达式至少出现m次,至多n次
比较特殊的是,gawk需要指定 - -re - interval 命令选项才可以识别正则表达式间隔。示例:
$ echo "bt" | gawk --re -interval '/be{1}t/{print $0}'
$ echo "bet" | gawk --re -interval '/be{1}t/{print $0}'
bet
$ echo "bt" | gawk --re -interval '/be{1,2}t/{print $0}'
$ echo "bet" | gawk --re -interval '/be{1,2}t/{print $0}'
bet
4. 管道符号
简单说一句话:管道符表示or(或)的关系,只需满足其中一个即可。示例如下:
$ echo "The cat is asleep" | gawk '/cat|dog/{print $0}'
The cat is asleep
$ echo "The dog is asleep" | gawk '/cat|dog/{print $0}'
The dog is asleep
$ echo "The sheep is asleep" | gawk '/cat|dog/{print $0}'
$
5. 圆括号-表达式分组
圆括号可以实现正则表达式的分组,分组后,每个组会被视为一个标准字符。看示例说话:
# 圆括号里面的字符可视为一个整体
$ echo "Sat" | gawk '/Sat(urday)?/{print $0}'
Sat
$ echo "Saturday" | gawk '/Sat(urday)?/{print $0}'
Saturday
Linux基础部分打算暂且就学这么多先,下一篇开始转录组学数据的实操。