说到“正则表达式”(简称RegExp),它又是一个极具UNIX STYLE的超级武器。RegExp的内容极为广泛与庞杂,若要精通它,恐怕要跟精通C语言的难度相当。许多讲述RegExp的教材的作者自己就对它一知半解、不得真要,所以写出来的教材也让学生看得云里雾里、稀里糊涂,更是完全无法发挥这套武器的强大威力。本人根据自己多年在UNIX?-like系统上的琢磨和捣鼓,或许可以用最简洁、最切中要害的方法,向你们解明RegExp的基本精义。
※在当前的FreeBSD系统中,虽然/usr/bin/grep与/usr/bin/egrep两个程序完全一致,但要用到egrep(扩充语法的grep),还是必须显式地使用egrep命令,或用“grep -E”。下面的内容,是针对egrep的(更简单、更强大)。
—— 只要八个汉字:
转义、数量、位置、逻辑
(0)正则表达式的目的,在于用它自己寻找到目标文本中符合某种特征的字符串,这种“寻找”的过程,也叫“扫描”,一旦寻找到,则就叫“匹配”。这跟之前介绍的“通配符”很相似,但正则表达式机制远比后者更复杂、更强大。正则表达式犹如一个模板一样,去圈套一切符合它样式的内容,所以,它也叫Pattern(模式、模板)。
(1)转义 —— 用元字符指代一类具有特性的字符的机制。一般通过中括号、小数点、反斜杠这些特殊符号(就是所谓的Meta Character,元字符)的序列来实现。
中括号 —— 类似于之前介绍的通配符中的。比如:模板“[a-z]”可以匹配26个小写英文字母中的任何单一字符;模板“[^A-D]”可以匹配大写英文字母A-D之外的任何单一字符。
小数点 —— 除了“换行”(\n)之外的任何单一字符。比如:模板“^.{5}$”可以匹配任何正好有5个字符的行。
反斜杠序 —— 这是典型的转义序列:序列“\w”等效于“[a-zA-Z0-9_]”;序列“\W”则等效于“[^a-zA-Z0-9_]”。
(2)数量 —— 用来指定被匹配的字符(串)的数量。一般通过花括号、星号、加号和问号这些元字符来实现:
花括号—— 描述字符出现多少次将会被匹配。{m,n}表示m次或n次或两者之间的任意次数;{m,}表示大于等于m的次数;{,n}表示小于等于n的次数;{m}表示有且仅有m次。比如:模板“s{2,3}”可以匹配字符串“ss”、“sss”。
星号 —— 意同{0,},即0次或任意正次数。比如:模板“As*”可以匹配字符串“A”、“As”、“Ass”。
加号 —— 意同{1,},即1次或其他任意正次数。比如:模板“As+” 可以匹配字符串“As”、“Ass”但不能匹配“A”。
问号 —— 要么有1次,要么有0次。比如:模板“as?\>” 可以匹配文本“a man as an ass”中的字符串“a”、“as”,但不能匹配“ass”或“an”。
※ 所有表示数量的元字符,作用且仅作用在紧挨在它左边的第一个(或第一个分组)字符的身上,比如:“foo.*”里的“*”仅仅作用在“.”身上,而不是“foo.”身上。
(3)位置 —— 用来匹配到指定位置的字符串。一般通过以下两对元字符来实现:
补脱符(^,Caret,[Shift]+[6]) —— 表示BOL(Begin of Line),比如:模板“^Hello”只能匹配位于行首的字符串“Hello”,在非行首出现的字符串“Hello”将不能被匹配。美元符 —— 与补脱符相反,表示EOL(End of Line)。
\<(反斜杠加一个小于号)——描述了这么一种位置:若有一个字符串处于它左边的空白或标点之右,该字符串将被“\<字符串”这样的模板匹配。比如:模板“\”的意义正相反,比如:模板“Windows\>” 将匹配“Windows 98”中的字符串“Windows”,但“Windows98”中的字符串“Windows”却不能被匹配。
其实,关于“位置”的模板表达,有一种非常易于识记的方法:将一行的行首、行尾这些“看不见字符”的东东,以及用于分割单词的某种空间,想象为可以某种“摸得着”的特殊字符,那么,这些特殊字符就是“^”、“$”、“\<”、“\>”,把那些原本难以表达的概念,转化为实体字符,然后将这种字符,安插在它们的对应位置,就没错了!
(4)逻辑。主要内容只有两个:
小括号 —— 用来分组,即将被它括起来的字符串视为一个整体。
管道符 —— 两项被管道符(|)黏结的字符串组成的模板,表示要么用左边一项字符串来匹配,要么用右边一项字符串来匹配。
比如:可以用模板“^[0-9]{6}(1970|1972)[0-9]{8}$”匹配文本中所有其出生年份信息是1970年或1972年的身份证号码行,当然可以可以模板“^[0-9]{6}197[02][0-9]{8}$”。
在grep命令行中,如果模板中的某些字符(比如小于号、大于号等)会引起Shell出现我们所不期望的解读(发生了歧义),我们就应该用双引号将Pattern括起来。然而,在csh中,用双引号括起某些特殊符号(比如美元符)反而又会引起Shell的解读问题,倒是用单引号却不会有问题。所以,当我们怀疑Shell误解了我们向grep程序提供的Pattern的时候,我们应当用其他的方案反复测试与验证,以确认是否发生了“歧义”。
阅读(928) | 评论(0) | 转发(0) |