zoukankan      html  css  js  c++  java
  • 【转】浅说matlab的正则表达式

     http://hi.baidu.com/daihaipengdhp/blog/item/16dbf417a950650dc93d6db4.html


    引言.啥是正则表达式?正则表达式是干啥的?
    我理解就和我们在word或者其他编辑软件里点的查找、替换的作用是差不多的,不过功能要强大的多,当然使用起来也稍微复杂一些。
    书上的定义差不多是这样的:正则表达式就是一个表达式(也是一串字符),它定义了某种字符串模式。利用正则表达式,可以对大段的文字进行复杂的查找、替换等。
    matlab提供的正则表达式函数有三个:
    regexp——用于对字符串进行查找,大小写敏感;
    regexpi——用于对字符串进行查找,大小写不敏感;
    regexprep——用于对字符串进行查找并替换。

    稍微介绍一下这三个函数,以regexpi为例,也可以先跳过这里,看过正文之后回头再来看看这里。

    [start end extents match tokens names] = regexpi('str', 'expr')
    start为匹配字符串的起始位置;end为匹配字符串的终止位置;extents为扩展内容,和'tokens'指示符一起用,指示出现tokens的 位置;match即找到的匹配字串;tokens匹配正则表达式中标记(tokens)的字串;names为匹配到的命名标记的标记名。

    若不需要所有的输出,可以用下面的方式指定所需输出。
    [v1 v2 ...] = regexpi('str', 'expr', 'q1', 'q2', ...)
    'q1','q2',...为'start','end','tokens','tokensExtents','match','names'之一,意义与上面的解释一样。v1,v2...的输出顺序与q1,q2...一致。


    第一部分——单个字符的匹配
    我们先从简单的开始——以regexpi函数为例。假设你要搜索一个包含字符'cat'的字符串,搜索用的正则表达式就是'cat'。如果搜索对大小写不敏感,单词'catalog'、'Catherine'、'sophisticated'都可以匹配。也就是说:
    正则表达式:'cat'
    匹配:'cat', 'catalog', 'Catherine','sophisticated'
    这个好像和我们通常在记事本里ctrl+F弄出来的东西差不多哈,呵呵。。。(btw:为了方便,下面的叙述中字符串和正则表达式的''都省略不写。)
    1   句点符号 '.' ——匹配任意一个(只有一个)字符(包括空格)。
    假设你在玩英文拼字游戏,想要找出三个字母的单词,而且这些单词必须以't'字母开头,以'n'字母结束。另外,假设有一本英文字典,你可以用正则表达式 搜索它的全部内容。要构造出这个正则表达式,你可以使用一个通配符——句点符号'.'。这样,完整的表达式就是t.n,它匹配tan、 ten、tin和ton,还匹配t#n、tpn甚至t n,还有其他许多无意义的组合。这是因为句点符号匹配所有字符,包括空格:
    小整理:正则表达式:t.n
           匹配:ten, tin, ton, t n, tpn, t#n, t@n
    Matlab例子程序:
    clear;clc
    str='ten,&8yn2tin6ui>&ton, t n,-356tpn,$$$$t#n,4@).,t@nT&nY';
    pat='t.n';
    o1=regexpi(str,pat,'start')%用'start'参数指定输出o1为匹配正则表达式的子串的起始位置
    o2=regexpi(str,pat,'end')%用'start'参数指定输出o1为匹配正则表达式的子串的结束位置
    o3=regexpi(str,pat,'match')%用'match'参数指定输出o2为匹配正则表达式的子串             
    [o11,o22,o33]=regexpi(str,pat,'start','end','match') %同时输出起始位置和子串
    输出为:
    o22 =
        3     8 13 18 23 28 33 36
    o33 =
    'ten' 'tin' 'ton' 't n' 'tpn' 't#n' 't@n' 'T&n'
    o1 =
        1 10 18 23 31 39 48 51
    o2 =
        3 12 20 25 33 41 50 53
    o3 =
    'ten' 'tin' 'ton' 't n' 'tpn' 't#n' 't@n' 'T&n'
    o11 =
        1 10 18 23 31 39 48 51
    o22 =
        3 12 20 25 33 41 50 53
    o33 =
    'ten' 'tin' 'ton' 't n' 'tpn' 't#n' 't@n' 'T&n'
    2 方括号符号 '[oum]' ——匹配方括号中的任意一个
    为了解决句点符号匹配范围过于广泛这一问题,你可以在方括号('[]')里面指定看来有意义的字符。此时,只有方括号里面指定的字符才参与匹配。也就是 说,正则表达式t[aeio]n只匹配tan,Ten,tin和toN等。但'Tmn','taen'不匹配,因为在方括号之内你只能匹配单个字符:
    小整理:正则表达式:t[aeio]n
           匹配:tan, ten, tin, ton
    matlab 例子程序:
    clear;clc
    str='ten,&8yn2tin6ui>&ton, t n,-356tpn,$$$$t#n,4@).,t@nT&nY';
    pat='t[aeiou]n';
    o1=regexpi(str,pat,'start')%用'start'参数指定输出o1为匹配正则表达式的子串的起始位置
    o2=regexpi(str,pat,'end')%用'start'参数指定输出o1为匹配正则表达式的子串的结束位置
    o3=regexpi(str,pat,'match')%用'match'参数指定输出o2为匹配正则表达式的子串             
    [o11,o22,o33]=regexpi(str,pat,'start','end','match') %同时输出起始位置和子串
    输出结果为
    o1 =
        1 10 18
    o2 =
        3 12 20
    o3 =
    'ten' 'tin' 'ton'
    o11 =
        1 10 18
    o22 =
        3 12 20
    o33 =
    'ten' 'tin' 'ton'
    3   方括号中的连接符 '[c1-c2]' ——匹配从字符c1开始到字符c2结束的字母序列(按字母表中的顺序)中的任意一个。
    如[a-c]匹配a,b,c,A,B,C
    即:正则表达式:t[a-z]n
    匹配:tan, tbn,tcn,tdn,ten,…, txn, tyn,tzn
    matlab 例子程序:
    clear;clc
    str='ten,&8yn2tin6ui>&ton, t n,-356tpn,$$$$t#n,4@).,t@nT&nY';
    pat='t[a-z]n';
    o1=regexpi(str,pat,'start')%用'start'参数指定输出o1为匹配正则表达式的子串的起始位置
    o2=regexpi(str,pat,'end')%用'start'参数指定输出o1为匹配正则表达式的子串的结束位置
    o3=regexpi(str,pat,'match')%用'match'参数指定输出o2为匹配正则表达式的子串             
    [o11,o22,o33]=regexpi(str,pat,'start','end','match') %同时输出起始位置和子串
    4   \n 等 ——特殊字符
    就是由'\'引导的,代表有特殊意义或不能直接输入的单个字符。在使用printf函数输出时我们常用'\n'来代替回车符,这里也是 同样的道理,用\n在正则表达式中表示回车符。类似的还有\ t横向制表符,'\*'表示'*'等。后一种情况用在查询在正则表达式中有语法作用的字符。详见下文。
    下面是一些匹配单个字符的转义字符正则表达式及所匹配的值。
    \xN或\x{N} 匹配八进制数值为N的字符
    \oN或\o{N} 匹配十六进制数值为N的字符
    \a Alarm(beep)
    \b Backspace
    \t 水平Tab
    \n New line
    \v 垂直Tab
    \f 换页符
    \r 回车符
    \e Escape
    \c 某些在正则表达式中有语法功能或特殊意义的字符c,要用\c来匹配,而不能直接用c匹配,如.用正则表达式\.匹配,而\用正则表达式\\匹配
    matlab程序例子
    clear;clc
    str='l.[a-c]i.$.a';
    pat1='.';pat2='\.';
    o=regexpi(str,pat1,'match')
    o1=regexpi(str,pat2,'match')
    输出为:
    o =
    'l' '.' '[' 'a' '-' 'c' ']' 'i' '.' '$' '.' 'a'
    o1 =
    '.' '.' '.'
    5   \w,\s和\d——类表达式
    和上面的\n等表中的转义字符有所不同,\w,\s,\d等匹配的不是某个特定的字符,而是某一类字符。具体说明如下:
    \w匹配任意的单个文字字符,相当于[a-zA-Z0-9_];
    \s匹配任意的单个空白字符,相当于[\t\f\n\r];
    \d匹配任意单个数字,相当于[0-9];
    \S匹配除空白符以外的任意单个字符,相当于[^\t\f\n\r]——方括号中的^表示取反;
    \W匹配任意单个字符,相当于[^a-zA-Z0-9_];
    \D匹配除数字字符外的任意单个字符,相当于[^0-9]。
    matlab程序例子,这里引用的是matlab帮助中的例子:
    str='easy as 1,2,3';%这个字符串可真有点意思,呵呵
    pat='\d';
    [o1,o2]=regexpi(str,pat,'start','match')
    输出结果为:
    o1 =
        9 11 13
    o2 =
    '1' '2' '3'

    第二部分串的匹配
    1. 多次匹配
    比如,我们要匹配'ppp',那么就可以用正则表达式'ppp',还有一种更简单一点的记法'p{3}'。正则表达式中的'{}'用来表示匹配前面的表达 式的出现次数。就是说,'p{2,3}',匹配'pp'和'ppp'。除了'{}',还有几个字符,用在表示单个字符的正则表达式后面表示次数,详见下 表,表中的expr表示第一部分我们讲过的所有表达式。
    expr? 与expr匹配的元素出现0或1次,相当于{0,1}
    expr* 与expr匹配的元素出现1次或更多,相当于{0,}
    expr+ 与expr匹配的元素出现1次或更多,相当于{1,}
    expr{n} 与expr匹配的元素出现n次,相当于{n,n}
    expr{n,} 与expr匹配的元素至少出现n次
    expr{n,m} 与expr匹配的元素出现n次但不多于m次
    假设我们要在文本文件中搜索美国的社会安全号码。这个号码的格式是999-99-9999。用来匹配它的正则表达式如图所示。在正则表达式中,连字符 (“-”)有着特殊的意义,它表示一个范围,比如从0到9。因此,匹配社会安全号码中的连字符号时,它的前面要加上一个转义字符“\”。完整的正则表达式 为[0-9]{3}\-[0-9]{2}\-[0-9]{4}
    假设进行搜索的时候,你希望连字符号可以出现,也可以不出现——即,999-99-9999和999999999都属于正确的格式。这时,你可以在连字符号后面加上“?”数量限定符号。完整的正则表达式为[0-9]{3}\-?[0-9]{2}\-?[0-9]{4}
    下面我们再来看另外一个例子。美国汽车牌照的一种格式是四个数字加上二个字母。它的正则表达式前面是数字部分“[0-9]{4}”,再加上字母部分“[A-Z]{2}”。完整的正则表达式为[0-9]{4}[A-Z]{2}
    另外,当我们使用expr*时,matlab将尽可能的匹配最长的字符子串。如:
    str = '<tr valign=top><td><a name="19184"></a>xyz';
    regexp(hstr, '<.*>', 'match')
    ans =
    '<tr valign=top><td><a name="19184"></a>'
    如果我们希望匹配尽可能短的字符子串时,可以在上面我们使用的字符串后使用'?',也就是expr*?,如:
    str = '<tr valign=top><td><a name="19184"></a>xyz';
    regexp(hstr, '<.*?>', 'match')
    ans =
    '<tr valign=top>' '<td>' '<a name="19184">' '</a>'
    还有一种是expr*+ ,这种表达式的用法很诡异,没弄懂在什么地方有用。如果哪位大侠有高见,望不吝赐教!
    这个表达式的执行过程是这样的,先执行expr*,“游标”(如果有的话)就指到了与expr*匹配的字符子串的最末端,然后从那里开始再检查下一个字符与后面的表达式是否匹配,如果匹配就继续向前(如果一直成功则返回最长的字符串),如果不匹配则直接返回空。例如:
    str = '<tr valign=top><td><a name="19184"></a>xyz';
    regexp(hstr, '<.*+>', 'match')
    ans =
        {}
    regexp(hstr, '<.*+', 'match')
    ans =
    '<tr valign=top><td><a name="19184"></a>xyz'
    2.   逻辑运算符
    简单的例子比如'exp|exp2',表示或者满足exp或者满足exp2。还有其他一些正则表达式之间的关系如下:
    (expr) 将expr标记为一组、匹配expr,并将匹配的字符子串标记起来以供后面使用。——关于这部分内容第三部分(tokens)还会有详细介绍
    (?:expr) 说明expr为一组,相当于数学表达式中的()
    例如:>>lstr='A body or collection of such stories';
       >>regexp(lstr,'(?:[^aeiou][aeiou]){2,}','match')
    ans =
    'tori'
    上面的表达式中{2,}对[^aeiou][aeiou]起作用,如果去掉分组,则只对[aeiou]起作用,如下所示:
    >>regexp(lstr,'[^aeiou][aeiou]{2,}','match')
    ans =
    'tio' 'rie'
    (?>expr) expr中的每个元素是一个分组
    (?#expr) 这个比较容易理解啦,就是expr放在(?#和)之间是就是注释。如:
    >>regexp(lstr, '(?# Match words in caps)[A-Z]\w*', 'match')
    ans =
    'A'
    expr1|expr2 匹配两者之一即可,expr1或者expr2
    >>regexp(hstr, '[^aeiou\s]o|[^aeiou\s]i', 'match')
    ans =
    'bo' 'co' 'ti' 'to' 'ri'
    ^expr 匹配expr,并且出现在原字符串最前端的子串
    expr$ 匹配expr,并且出现在原字符串最末端的子串
    >>regexpi(lstr, '^a\w*|\w*s$', 'match')
    ans =
    'A' 'stories'
    \<expr 匹配expr,并且出现在一个单词最前端的子串
    >>regexpi(hstr, '\<s\w*', 'match')
    ans =
    'such' 'stories'
    expr\> 匹配expr,并且出现在一个单词最末端的子串
    >>regexpi(hstr, '\w*tion\>', 'match')
    ans =
    'collection'
    \<expr\> 更严格的单词匹配,如:以s开头,并且以h结尾的单词
    >>regexpi(hstr, '\<s\w*h\>', 'match')
    ans =
    'such'
    3.   左顾右盼——利用上下文匹配
    这个也比较容易理解。就是利用上下文的匹配来找到我们要找的内容。
    expr1(?=expr2) 找到匹配expr1的子串,如果其后的字符串也匹配expr2
    如,下面的例子查找所有在','之前的单词。
    >> pstr = ['While I nodded, nearly napping, ' ...
          'suddenly there came a tapping,'];
    >>regexpi(pstr, '\w*(?=,)', 'match')
    ans =
    'nodded' 'napping' 'tapping'
    expr1(?!expr2) 找到匹配expr1的子串如果其后的字符串不匹配expr2
    下面的例子匹配所有不在','之前的单词
    >>regexpi(pstr, '\w*(?!=,)', 'match')
    ans =
       Columns 1 through 6
    'While' 'I' 'nodded' 'nearly' 'napping' 'suddenly'
       Columns 7 through 10
    'there' 'came' 'a' 'tapping'
    (?<=expr1)expr2 找到匹配expr2的子串,如果其前面的字符串也匹配expr1
    下面的例子查找所有在','之后的单词,注意:','之后可能有空格
    >>regexpi(pstr,'(?<=,\s*)\w*','match')
    ans =
    'nearly' 'suddenly'
    (?<!expr1)expr2 找到匹配expr2的子串,如果其后的字符串不匹配expr1
    下面的例子查找所有不在','之后的单词,
    >>regexpi(pstr,'(?<!,\s*)\w*','match')
    ans =
       Columns 1 through 6
    'While' 'I' 'nodded' 'early' 'napping' 'uddenly'
       Columns 7 through 10
    'there' 'came' 'a' 'tapping'

    第三部分标记(tokens)
    这部分是比较难的一部分,个人感觉。我也是勉强弄的,有什么不妥或错误往指正、海涵。
    1.   什么是标记(token)?
       任何的正则表达式都可以用圆括号括起来作为一个标记。例如,创建一个记录钱数的标记,就可以用($\d+)。这样与之匹配的字符串就会被记录下来,根据这 个标记出现的顺序,可以使用\n来引用匹配这个标记的字符串。如\3来引用与标记相匹配的第三个字符串。(如果在替换函数regexprep中,需要用 $3来引用。)
    下面是一个例子,\S查找任意的非空白字符,\1的用法比较精髓——它用来说明要立即再次查找刚刚匹配到的同一个字符,并且要紧挨着第一个。'tokens'选项用来向tok输出所有匹配到的标记;而'tokenExtents'则用来表示匹配标记的起始位置。
       >>poestr = ['While I nodded, nearly napping, suddenly there came a tapping,'];
       >>[mat tok ext] = regexp(poestr, '(\S)\1', 'match', 'tokens', 'tokenExtents');
       >>mat
       mat =
       'dd' 'pp' 'dd' 'pp'
       >>tok{:}
       ans =
       'd'
       ans =
       'p'
       ans =
       'd'
       ans =
       'p'
       >>ext{:}
       ans =
       11 11
       ans =
       26 26
       ans =
       35 35
       ans =
    57 57
    2.   如何使用标记?
    (expr) 记录所有匹配表达式的字符,并做为一个标记,以备后面使用
    这个例子说明了标记的生成过程:
       >>pstr='andy ted bob jim andrew andy ted mark';
       >> [t,m]=regexp(pstr,pat,'tokens','match')
       t =
       {1x1 cell} {1x2 cell} {1x1 cell} {1x1 cell} {1x2 cell}
       m =
       'andy' 'ted' 'andrew' 'andy' 'ted'
       >> t{:}
       ans =
       'y'
       ans =
       't' 'd'
       ans =
       'rew'
       ans =
       'y'
       ans =
       't' 'd'
    \N           匹配同一条正则表达式里的第N个标记中的字符串。如\1匹配第一个标记;
           一个例子,用来查找html语句中类似<a>abc</a>的部分:
                 >>hstr = '<!comment><tr nam="7507"></tr><table>Default</table><br>';
                 >>expr = '<(\w+).*?>.*?</\1>';
                 >> [mat tok] = regexp(hstr, expr, 'match', 'tokens');
                 >> mat{:}
                 ans =
                 <tr nam="7507"></tr>
                 ans =
                 <table>Default</table>
                 >> tok{:}
                 ans =
                   'tr'
                 ans =
                   'table'
    $N 在一个替换字符串中插入与第N个标记相匹配的字符串(只用于regexprep函数)
       一个例子,将匹配到的第一个token和第二个token的位置互换:
       >> regexprep('Norma Jean Baker', '(\w+\s\w+)\s(\w+)', '$2, $1')
           ans =
             Baker, Norma Jean
    (?<name>expr) 记录所有匹配表达式expr的字符,做为一个标记,并设定一个名字name
    \k<name>     与名为name的标记相匹配
       这个例子和这部分第一个例子是一样的,只不过使用了命名的标记。
       >>poestr = ['While I nodded, nearly napping, ' ...
                 'suddenly there came a tapping,'];
       >>regexp(poestr, '(?<nonwhitechar>\S)\k<nonwhitechar>', 'match')
       ans =
        'dd' 'pp' 'dd' 'pp'
    (?(tok)expr) 如果标记tok已经产生,则匹配表达式expr。if-then结构。其中的标记可以是数字标记,也可以是命名标记
    (?(tok)expr1|expr2) 如果标记tok已经产生,则匹配表达式expr1,否则匹配表达式expr2。if-then-else结构
                 这个例子有点意思,是用来检查一个句子中的性别用词是否匹配,表达式的意思就是,如果前面用的是'Mrs'那么后面就匹配                             'her',如果前面用的是'Mr'(也就是没有匹配到'Mr'后面的's',则后面匹配'his')。
                 >>expr = 'Mr(s?)\..*?(?(1)her|his) son';
                 >>[mat tok] = regexp('Mr. Clark went to see his son', expr, 'match', 'tokens')
                 mat =
                   'Mr. Clark went to see his son'
                 tok =
                   {1x2 cell}
                 >>tok{:}
                 ans =
                   '' 'his'
                 如果把句子中的his改成her,则结果如下:
                >>[mat tok] = regexp('Mr. Clark went to see her son', expr, 'match', 'tokens')
                 mat =
                   {}
                 tok =
                   {}
                 没有与之匹配的结果,呵呵。。。

    第四部分多行字符串与多正则表达式
    这是最后一部分,也是最容易的一部分了。
    1. 多字符串与单个正则表达式匹配
    多个字符串存在一个元胞数组里之后,每一个字符串与正则表达式匹配,返回值的维数与元胞数组相同。
    >>cstr = {                               ...
    'Whose woods these are I think I know.' ; ...
    'His house is in the village though;' ; ...
    'He will not see me stopping here'    ; ...
    'To watch his woods fill up with snow.'};
    >>idx = regexp(cstr, '(.)\1');
    >>idx{:} ans =                 % 'Whose woods these are I think I know.'
    8                 %       |8
    ans =                 % 'His house is in the village though;'
    23                 %                      |23
    ans =                 % 'He will not see me stopping here'
    6 14 23     %    |6    |14    |23
    ans =                 % 'To watch his woods fill up with snow.'
    15 22           %             |15 |22
    2. 多个字符串与多个正则表达式匹配
    这种情况下,应该满足字符串元胞数组中字符串的个数和正则表达式的个数相等——但维数不一定要相等——如可以用4*1的元胞数组与1*4的正则表达式相匹配。
    expr = {'i\s', 'hou', '(.)\1', '\<w[aeiou]'};
    idx = regexpi(cstr, expr);
    idx{:}
    ans =                 % 'Whose woods these are I think I know.'
    23 31           %                      |23     |31
    ans =                 % 'His house is in the village though;'
    5 30           %    |5                       |30
    ans =                 % 'He will not see me stopping here'
    6 14 23     %    |6    |14    |23
    ans =                 % 'To watch his woods fill up with snow.'
    4 14 28     %     |4        |14           |28
    3. 多字符串的替换
    这个就是在匹配的基础上,在正则表达式后面加入要替换的字符串就ok啦。
    这个是matlab中的例子,很容易理解。
    >>s = regexprep(cstr, '(.)\1', '--', 'ignorecase')
    s =
    'Whose w--ds these are I think I know.'
    'His house is in the vi--age though;'
    'He wi-- not s-- me sto--ing here'
    'To watch his w--ds fi-- up with snow.

    ok. That'all.GoOd Luck~~
  • 相关阅读:
    【C++】资源管理
    【Shell脚本】逐行处理文本文件
    【算法题】rand5()产生rand7()
    【Shell脚本】字符串处理
    Apple iOS产品硬件参数. 不及格的程序员
    与iPhone的差距! 不及格的程序员
    iPhone游戏 Mr.Karoshi"过劳死"通关. 不及格的程序员
    XCode V4 发布了, 苹果的却是个变态. 不及格的程序员
    何时readonly 字段不是 readonly 的?结果出呼你想象!!! 不及格的程序员
    object file format unrecognized, invalid, or unsuitable Command 不及格的程序员
  • 原文地址:https://www.cnblogs.com/fzzl/p/1428585.html
Copyright © 2011-2022 走看看