日历

2018年十二月
« 11月    
 12
3456789
10111213141516
17181920212223
24252627282930
31  

最近评论

    linux/unix基础知识

    正则表达式简介

         为什么要使用正则表达式
        linux/UNIX中提供了许多命令和工具,它们可以在文件中查找(Search)字符串或替换(Replace)字符串的功能。像grep,vi,sed,awk等,不论是查找字符串还是替换字符串,都得先告诉这些命令所要查找(被替换)的字符串是什么,如果未能事先明确知道所要查找(被替换)的字符串是什么,只知道这个字符串存在的范围或特征时,例如:(一)查找”T0.c”,”T1.c”,”T2.c”…”T9.c” 当中的任一字符串。(二)查找至少存在一个”A”的任意字符串。这种情況下,如何告诉执行查找字符串的命令所要查找的字符串是什么。例(一) 中,要查找任一在”T”与”.c” 之间存在一个阿拉伯数字的字符串;当然可以用列举的方式,一一把所要查找的字符串告诉执行命令的命令。但例(二) 中符合该条件的字符串有无限种可能,势必无法一一列举。此时,便需要另一种字符串表示的方法。

        什么是正则表达式:正则表达式(以下简称Regexp)是一种字符串表达的方式。可以指定具有某特征的所有字符串。
        注:为了与一般字符串区别,在这里,在正则表达式的字符串之前皆加 “Regexp”。
        awk程序中常以/…/括住Regexp,以区別于一般字符串。

        组成正则表达式的元素:普通字符除了 . * [ ] + ? ( ) \  ^ $ 外的所有字符。由普通字符所组成的Regexp的意义与原字符串字面意义相同。例如:Regexp “the” 与一般字符串的”the” 代表相同的意义。
        (Meta character) :用来代表任意一字符。在linux/unix Shell中使用 “*”表示0个或任意长度的字符。
        在Regexp中:
        “.” 代表任意一个字符
        “*” 另有其它涵意,并不代表任意长度的字符串
        ^ 表示该字符串必须出现于行首
        $ 表示该字符串必须出现于行末。
        例如:Regexp/^The/用来表示所有出现于行首的字符串”The”。Regexp/The$/ 用来表示所有出现于行末字符串”The”。
        \将特殊字符还原成字面意义的字符(Escape character) ,Regexp中特殊字符将被解释成特定的意义。如果要表示特殊字符的字面(literal meaning)意义时,在特殊字符之前加上”\”即可。例如:使用Regexp来表示字符串”a.out”时,不可写成 /a.out/,因为”.”是特殊字符,表示任意一个字符。可符合Regexp / a.out/的字符串将不只 “a.out” 一个;字符串”a2out”,”a3out”,”aaout”…都符合 Regexp /a.out/, 正确的用法为:/ a\.out/。

        […]字符集合,用来表示两中括号间所有的字符当中的任一个。
        例如:Regexp/[Tt]/可用来表示字符”T” 或 “t”。所以Regexp/[Tt]he/,表示字符串”The” 或 “the”。字符集合[…] 內不可随意留空白。例如:Regexp/[ Tt ]/,其中括号內有空白字符,除表示”T”,”t” 中任一个字符,也可代表一个” “(空白字符) 。
        字符集合中可使用”-” 来指定字符的区间,其用法如下:Regexp /[0-9]/等于/[0123456789]/,用来表示任意一个阿拉伯数字。同理Regexp/[A-Z]/ 用来表示任意一个大写英文字母。但要注意,Regexp /[0-9a-z]/并不等于/[0-9][a-z]/;前者表示一个字符,后者表示二个字符。Regexp/[-9]/或/[9-]/只代表字符,”9″或 “-“。
        [^…]使用[^…] 产生字符集合的补集(complement set)。其用法如下:例如:要指定”T”或”t”之外的任一个字符,可用/[^Tt]/表示。同理Regexp/[^a-zA-Z]/,表示英文字母之外的任一个字符。
        注意”^” 的位置:”^”必须紧接在”[“之后,才代表字符集合的补集。例如:Regexp /[0-9\^]/只是用来表示一个阿拉伯数字或字符”^”。

        * 表示字符重复次数的特殊字符。”*” 表示它前方之字符可出现0次或任意多次,即字符大于等于0次。例如:Regexp/T[0-9]*\.c/中,*表示其前[0-9](一个阿拉伯数字)出现的次数可为0次或多次。所以Regexp /T[0-9]*\.c/可用来表示”T.c”,”T0.c”,”T1.c”…”T19.c” 。

        +表示其前的字符出现一次或一次以上。例如:Regexp /[0-9]+/ 用来表示一位或一位以上的数字。

        ? 表示其前的字符可出现一次或不出现。例如:Regexp /[+-]?[0-9]+/ 表示数字(一位以上)之前可出现正负号或不出现正负号。

        (…)用来括住一群字符,且把他当成一个group。例如:Regexp /12+/ 表示字符串”12″,”122″,”1222″,”12222″,…。egexp /(12)+/ 表示字符串 “12”,”1212″,”121212″,”12121212″…。上式中12 以( )括住,所以”+” 所表示的是12,重复出现的也是12。

        | 表示逻辑上的”或”(or) 。例如:Regexp/ Oranges?|apples?|water/可用来表示:字符串  “Orange”,”Oranges” 或 “apple”,”apples”  或 “water” 。

         match是什么? 讨论Regexp时,经常遇到”某字符串匹配( match )某Regexp”的字眼。意思是: “这个Regexp可被解释成该字符串”。[ 例如] : 字符串”the” 匹配(match) Regexp /[Tt]he/。因为 Regexp /[Tt]he/ 可解释成字符串 “the” 或 “The”,故字符串 “the”  或 “The”都匹配(match) Regexp /[Th]he/。

          awk 中提供二个关系运算符(Relational Operator):~ ,!~,它们也称之为match,not match。但函义与一般常说的match略有不同。其定义如下:A  表一字符串,B 表一Regular Expression,只要A 字符串中存在有子字符串可match( 一般定义的 match) Regexp B ,则A ~B 就算成立,其值为true,反之则为false。! ~ 的定义与~恰好相反。例如:”another” 中含有子字符串 “the” 可match Regexp /[Tt]he/,所以 “another” ~ /[Tt]he/ 之值为 true

        有些地方不把( ~,!~)与Relational  Operators 归为一类。

         应用Regular Expression 解题的简例:下面列出一些应用Regular Expression 的简例
        例1:将文件中所有的字符串 “Regular Expression” 或 “Regular  expression” 换成 “Regexp” 
    [root@myfreelinux pub]# cat regexp
    Regular expression
    Regular Expression
    [root@myfreelinux pub]# awk ‘{gsub(/Regular[ \t]+[eE]xpression/,”Regexp”);print $0;}’ regexp
    Regexp
    Regexp
        例2:去除文件中的空白行(或仅含空白字符或tab 的行)
    [root@myfreelinux pub]# cat regexp
    Regular expression
       
    Regular Expression
    [root@myfreelinux pub]# awk ‘{if($0!~/^[ \t]+$/) print $0;}’ regexp
    Regular expression
    Regular Expression
         例3:在文件中具有ddd-dddd (电话号码型态,d 表digital)的字符串前加上”TEL :
    [root@myfreelinux pub]# cat regexp
    83786550
    83786450
    [root@myfreelinux pub]# awk ‘{gsub(/[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]/,”TEL: &”);print $0;}’ regexp
    TEL: 83786550
    TEL: 83786450 
        例4:从文件的Fullname 中分离出路径与文件名
     [root@myfreelinux pub]# awk ‘BEGIN{Fullname=”/usr/local/apache2/bin/apachectl”;match(Fullname,/.*\//);path=substr(Fullname,1,RLENGTH-1);filename=substr(Fullname,RLENGTH+1);print Fullname;print path;print filename}’
    /usr/local/apache2/bin/apachectl
    /usr/local/apache2/bin
    apachectl
        例5:将某一数值改以现金表示法表示(整数部分每三位加一撇,且含二位小数)
     [root@myfreelinux pub]# awk ‘BEGIN{number=1234567890;number=sprintf(“¥%.2f”,number);while(match(number,/[0-9][0-9][0-9][0-9]/)) sub(/[0-9][0-9][0-9][.,]/,”,&”,number); print number}’
    结果输出 ¥1,234,567,890.00
          例6: 把文件中所有具”program数字.f”形态的字符串改为”[Ref :program数字.c]”
    [root@myfreelinux pub]# cat program
    program1.f
    program2.f
    program34.f
    program67.f
    [root@myfreelinux pub]# awk ‘{while(match($0,/program[0-9]+\.f/)){replace=”[Ref: “substr($0,RSTART,RLENGTH-2)”.c]”; sub(/program[0-9]+\.f/,replace);} print $0}’ program
    [Ref: program1.c]
    [Ref: program2.c]
    [Ref: program34.c]
    [Ref: program67.c]
    解释说明:以program1.f为例,while(match($0,/program[0-9]+\.f/))是匹配以下”program1.f”的文件名,匹配后结果会保存到RSTART=0和RLENGTH=10中;substr($0,RSTART,RLENGTH-2)就是去program1.f的前8位,即program1;replace=”[Ref: “substr($0,RSTART,RLENGTH-2)”.c]”的结果就是replace=“[Ref: program1.c]”;sub函数是用来进行代替的,也就是用[Ref: program1.c]代替program1.f。所以输出结果为上式的值。

    评论已关闭。