思考的轨迹

人若无名 专心练剑

正则表达式初学笔记

| Comments

最近一直在做MPEG2 TS-Mux,在开发调试的过程中有大量的log数据需要分析,特别是长时间测试,log文件往往会达到几百兆。

这时遇到问题,要自己逐行去分析log定位问题往往是不太现实的事情。

为了提高log文件分析的效率,我们利用Python编写分析log的脚本,每个脚本分析log文件中一类信息,如从前端Encoder中接受到的PTS,分析PTS是否有错误或跳变等情况。

为了从原始的log文件中提取出我们关心的log部分,使用了一个命令行工具Sed

Sed(streams editor)的具体使用方法可参考这篇文章sed命令+正则表达式

在一个数据量很大的文本中要查找出所有符合特定规则的文本,使用文本编辑器中简单查找功能往往很难达到要求。

不过现在的文本编辑器也越来越强大,我熟悉的如VIM、Notepad++、UltraEdit等都是支持使用正则表达式来完成复杂的、自定义规则的文本查找功能。 上述的Sed也是使用正则表达式来实现强大的文本查找功能。

下面将会简单介绍一些关于正则表达式的知识,以后有时间会写一篇关于如何使用Python和matplotlib库来分析log数据并图形化显示分析结果的文章。

对于正则表达式,我基本也是属于初学,这里主要是记录一下正则表达式的基本语法,学会如何使用这些基本语法来构建符合自己查找意图的正则表达式。

网上关于正则表达式的教程有很多,我主要参考了如下几篇:

什么是正则表达式?

正则表达式(Regular Expression),实际上就是一个描述待查找文本特征的字符串,这些字符串就构成了查找的规则,如下面的这些例子:

  • abc -> 描述了待查找文本的特征是:待查找的就是包含abc的文本

  • \d…\s123 -> 描述了待查找文本的特征是:以数字开关(在0至9范围内),后面跟3个任意字符,再跟一个任意类型的空格,之后跟着123

  • [1-9][0-9]{4, 11} -> 描述了待查找文本的特征是:以1至9范围内任一数字为开头,后面最少跟4个,最多跟11个数字(在0至9范围内)

  • \d{4}-?\d{7, 8} -> 描述了待查找文本的特征是:以4个数字开头,中间可以有也可以没有-,后面最少跟7个,最多跟8个数字(在0至9范围内)

如果之前没有接触过正则表达式,初次看到上述的这几个字符串,肯定不知所云,觉得莫名其妙。 没关系,我相信大多数人在开始学习正则表达式时会有这样的感觉。

实际上,通过上述的一些解释,我们可以看到正则表达式中使用了一些特殊的符号来表示一类字符,如使用\d来表示0至9范围内的数字等。

要想对正则表达式有深入了解,我们需要去学习一下正则表达式的基本语法,熟悉之后,我们就可以根据实际的需要来构建自己的正则表达式。

正则表达式的基本语法

注:文中的部分例子来自于正则表达式30分钟入门教程

元字符

元字符是正则表达式中一种特殊的字符,是用来表示其他字符的字符,实际查找的文本并不包含自身,相当于是信息的一种描述。

在正则表达式中,有如下几种元字符:

1
2
3
4
5
6
7
8
9
10
11
++++++++++++++++++++++++++++++++++++++++++++++++++++++
元字符    |     描述的特征
++++++++++++++++++++++++++++++++++++++++++++++++++++++
  .      |     匹配除换行符以外的任意字符
  \w     |     匹配字母或数字或下划线或汉字
  \s     |     匹配任意的空白符
  \d     |     匹配数字
  \b     |     匹配单词的开始或结束
  ^      |     匹配字符串的开始
  $      |     匹配字符串的结束
++++++++++++++++++++++++++++++++++++++++++++++++++++++

转义字符

元字符是用来表示其他的字符,而不能用来表达自身,因此,如果我们查找的文本中的确是要包含元字符时,这时就需要使用转义字符。

熟悉C/C++的同学应该对转义字符会很熟悉,转义字符就是使用反斜杠’'来取消元字符的特殊意义,而表达自身的一种方法,类似上述元字符中的\w,\s,\d,\b。

上述的这几个在形式上类似转义字符的元字符在实际中是不需要转义的,因为它们相当于是2个字符,而如果要查找的文本中要包含., ^, $,则需要转义., \, \$。

指定重复的次数

在正则表达式中,允许使用特殊的符合来指定其面前一个字符或一个组合单元重复的次数。

有如下几种指定重复次数的方法:

1
2
3
4
5
6
7
8
9
10
++++++++++++++++++++++++++++++++++++++++++++++++++++++
 限定符   |     描述的特征
++++++++++++++++++++++++++++++++++++++++++++++++++++++
   *     |     重复0零次或更多次
   +     |       重复1次或更多次
   ?     |     重复0次或1次
  {n}    |     重复n次
  {n,}   |     重复n次或更多次
  {n,m}  |     重复n到m次
++++++++++++++++++++++++++++++++++++++++++++++++++++++

指定字符集

如果我们事先知道在查找文本规则的特定位置的字符是在某个具体范围内,如某个位置上出现的字符只能是a,b,c,1,2,3中的一个时,正则表达式允许我们指定出这个字符集。

方法也很简单,就是将可能出现的字符放在方括号之中,如[abc123]即可。

对于连续的数字和字母,也可以用更简单的方法,如[0-9]表示出现的字符在数字0至9中的一个,类似的有[a-z],[A-Z]。

还可以将上面的组合起来,如[0-9a-zA-Z]。

正则表达式中的那些有特殊意义的符合也可以不用转义直接放在其中,如[.?+]可匹配., ?, +。

组合字符

我们已经知道,要重复单个字符,可直接在这个字符后加上指定重复次数的限定符即可。

如果我们要指定一组连续的字符的重复次数,该如何做呢?

方法是先将这组连续的字符放到圆括号()中,然后在后面加上指定重复次数的限定符就可以了。

如(abc){2},就描述了重复2次abc, 即abcabc。

更复杂的一个例子:(?0\d{2}[) -]?\d{8}

这个正则表达式可以这样来分析:

首先是一个转义字符(, 它能出现0次或1次(?), 然后是一个0,后面跟着2个数字(\d{2}),然后是)或-或空格中的一个,它出现1次或不出现(?),最后是8个数字(\d{8})。

匹配多个正则表达式中的一个

有时候一个正则表达式可能匹配出比我们预想要多的文本,如用于匹配电话号码的正则表达式(?0\d{2}[)-]?\d{8},不仅可匹配(010)88886666、022-22334455、02912345678等正常的号码,还会匹配出010)12345678或(022-87654321等这样的”不正确”的格式。

要解决这个问题,我们可以明确指定出每一种电话号码的匹配规则,各个匹配规则之间用’|’来分隔,这样只有符合指定规则中的一种时才会被匹配,这有点类似于C/C++中的’或’运算。

例如,0\d{2}-\d{8}|0\d{3}-\d{7}这个表达式能匹配两种以连字号分隔的电话号码:一种是三位区号,8位本地号(如010-12345678),一种是4位区号,7位本地号(0512-6733445)。

取反

如果我们事先知道要查找的文本中肯定没有哪些字符,或者是要匹配除了某某字符之外的任意字符这种情况时,我们可以用类似C/C++中的’取反’运算来实现。

正则表达式允许的’取反’:

1
2
3
4
5
6
7
8
9
10
++++++++++++++++++++++++++++++++++++++++++++++++++++++
元字符    |     描述的特征
++++++++++++++++++++++++++++++++++++++++++++++++++++++
  \W     |     匹配任意不是字母,数字,下划线,汉字的字符
  \S     |     匹配任意不是空白符的字符
  \D     |     匹配任意非数字的字符
  \B     |     匹配不是单词开头或结束的位置
 [^x]    |     匹配除了x以外的任意字符
 [^abc]  |     匹配除了abc这几个字母以外的任意字符
++++++++++++++++++++++++++++++++++++++++++++++++++++++

一些例子:

\S+ 匹配不包含空白符的字符串

<a[>]+> 匹配用尖括号括起来的以a开头的字符串

两种匹配模式:贪婪和懒惰

当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符。

例如,”a.*b” 它将会匹配最长的以a开始,以b结束的字符串。如果用它来搜索aabab的话,它会匹配整个字符串aabab。这被称为贪婪匹配。

如果我们希望匹配尽可能少的字符,只需在之前的限定符后加个问号’?’,这样将会以懒惰模式进行匹配。

例如,a.*?b 匹配最短的,以a开始,以b结束的字符串。如果把它应用于aabab的话,它会匹配aab(第一到第三个字符)和ab(第四到第五个字符)。

1
2
3
4
5
6
7
8
9
++++++++++++++++++++++++++++++++++++++++++++++++++++++
 限定符   |     描述的特征
++++++++++++++++++++++++++++++++++++++++++++++++++++++
   \*?   |     重复任意次,但尽可能少重复
   +?    |       重复1次或更多次,但尽可能少重复
   ??    |     重复0次或1次,但尽可能少重复
  {n,}?  |     重复n次以上,但尽可能少重复
  {n,m}? |     重复n到m次,但尽可能少重复
++++++++++++++++++++++++++++++++++++++++++++++++++++++

这些语法应该是正则表达式的最基础部分,还有一些高级的特性文中并没有涉及。

如果能够掌握并熟练使用上述的这些正则表达式的基本语法的话,我相信对于大多数的情况,正则表达式能够帮助我们快速的从复杂的文本中匹配出我们需要的内容。

从现在开始,慢慢感受正则表达式的强大吧!

(完)

Comments