学生信的那些事儿之九 - Linux基础之正则表达式

什么是正则表达式?

讲真"正则"这个词真的挺抽象,汉语里应该没有这个组合,不知道为什么这样翻译,倒是对应的英文更好理解一些。正则表达式( 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基础部分打算暂且就学这么多先,下一篇开始转录组学数据的实操。

你可能感兴趣的:(学生信的那些事儿之九 - Linux基础之正则表达式)