cinvent 发表于 2009-4-7 21:10

浅说matlab的正则表达式

浅说matlab的正则表达式

今天刚看到的一篇好关于matlab正则表达式的文章,个人感觉写的很好,不敢独享,拿出来和大家一块分享。

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

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

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

若不需要所有的输出,可以用下面的方式指定所需输出。
= 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为匹配正则表达式的子串            
=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 方括号符号 '' ——匹配方括号中的任意一个
为了解决句点符号匹配范围过于广泛这一问题,你可以在方括号('[]')里面指定看来有意义的字符。此时,只有方括号里面指定的字符才参与匹配。也就是说,正则表达式tn只匹配tan,Ten,tin和toN等。但'Tmn','taen'不匹配,因为在方括号之内你只能匹配单个字符:
小整理:正则表达式:tn
       匹配:tan, ten, tin, ton
matlab 例子程序:
clear;clc
str='ten,&8yn2tin6ui>&ton, t n,-356tpn,$$$$t#n,4@).,t@nT&nY';
pat='tn';
o1=regexpi(str,pat,'start')%用'start'参数指定输出o1为匹配正则表达式的子串的起始位置
o2=regexpi(str,pat,'end')%用'start'参数指定输出o1为匹配正则表达式的子串的结束位置
o3=regexpi(str,pat,'match')%用'match'参数指定输出o2为匹配正则表达式的子串            
=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结束的字母序列(按字母表中的顺序)中的任意一个。
如匹配a,b,c,A,B,C
即:正则表达式:tn
匹配: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='tn';
o1=regexpi(str,pat,'start')%用'start'参数指定输出o1为匹配正则表达式的子串的起始位置
o2=regexpi(str,pat,'end')%用'start'参数指定输出o1为匹配正则表达式的子串的结束位置
o3=regexpi(str,pat,'match')%用'match'参数指定输出o2为匹配正则表达式的子串            
=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.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匹配任意的单个文字字符,相当于;
\s匹配任意的单个空白字符,相当于[\t\f\n\r];
\d匹配任意单个数字,相当于;
\S匹配除空白符以外的任意单个字符,相当于[^\t\f\n\r]——方括号中的^表示取反;
\W匹配任意单个字符,相当于[^a-zA-Z0-9_];
\D匹配除数字字符外的任意单个字符,相当于[^0-9]。
matlab程序例子,这里引用的是matlab帮助中的例子:
str='easy as 1,2,3';%这个字符串可真有点意思,呵呵
pat='\d';
=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。因此,匹配社会安全号码中的连字符号时,它的前面要加上一个转义字符“\”。完整的正则表达式为{3}\-{2}\-{4}
假设进行搜索的时候,你希望连字符号可以出现,也可以不出现——即,999-99-9999和999999999都属于正确的格式。这时,你可以在连字符号后面加上“?”数量限定符号。完整的正则表达式为{3}\-?{2}\-?{4}
下面我们再来看另外一个例子。美国汽车牌照的一种格式是四个数字加上二个字母。它的正则表达式前面是数字部分“{4}”,再加上字母部分“{2}”。完整的正则表达式为{4}{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]){2,}','match')
ans =
'tori'
上面的表达式中{2,}对[^aeiou]起作用,如果去掉分组,则只对起作用,如下所示:
>>regexp(lstr,'[^aeiou]{2,}','match')
ans =
'tio' 'rie'
(?>expr) expr中的每个元素是一个分组
(?#expr) 这个比较容易理解啦,就是expr放在(?#和)之间是就是注释。如:
>>regexp(lstr, '(?# Match words in caps)\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,'];
   >> = 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';
   >> =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>';
             >> = 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';
             >> = 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,则结果如下:
            >> = 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'};
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~~

yelv123 发表于 2009-4-7 21:24

sogooda
版主好像在一个论坛写过相关的文章

ChaChing 发表于 2009-4-7 22:42

楼上的连接
http://forum.vibunion.com/forum/viewthread.php?tid=55817&highlight=
[原创]浅说matlab的正则表达式
怎麽内容一个样!?

sogooda 发表于 2009-4-7 22:56

回复 板凳 ChaChing 的帖子

呵呵

sogooda 发表于 2009-4-7 23:01

这个是稍微有点儿更新的版本,加了几个例子。


Matlab正则表达式零基础起步教程
Sogooda @ Simwe
摘    要:正则表达式是一个重要的编程概念。应用正则表达式可以实现很多强大的字符处理功能,有时也可以为常规方法解决起来比较复杂的问题另辟蹊径。本文试图通过比较详尽的示例为没有基础的读者介绍正则表达式的基本概念、用法及其在Matlab中的实现。文末附上几个应用表达式解决实际问题的实例,以利于读者在自己的实践中应用。
关 键 词:正则表达式Matlabregexp
0. 引言
正则表达式就是一个表达式(也是一串字符),它定义了某种字符串模式——利用正则表达式,可以对大段的文字进行复杂的查找、替换等。本文将以Matlab为编程语言,为您讲解正则表达式的概念和使用方法,并将在文末以实例说明正则表达式的实践应用。
Matlab提供的正则表达式函数有三个:
regexp——用于对字符串进行查找,大小写敏感;
regexpi——用于对字符串进行查找,大小写不敏感;
regexprep——用于对字符串进行查找并替换。
简要介绍一下这三个函数,以regexpi为例——您也可以先跳过这里,看过全文之后再来看这里。
用法1:
= regexpi('str', 'expr')
start为匹配字符串的起始位置;end为匹配字符串的终止位置;extents为扩展内容,和'tokens'指示符一起用,指示出现tokens的位置;match即找到的匹配字串;tokens匹配正则表达式中标记(tokens)的字串;names为匹配到的命名标记的标记名。
用法2:
若不需要所有的输出,可以用下面的方式有选择的输出。
= regexpi('str', 'expr', 'q1', 'q2', ...)
'q1','q2',...为'start', 'end', 'tokens', 'tokensExtents', 'match','names'之一,意义与前文相同。v1,v2...的输出顺序与q1,q2...一致。
1. 单个字符的匹配
我们先从简单的开始——以regexpi函数为例,不区分字符的大小写。假设你要搜索'cat',搜索用的正则表达式就是'cat',这文本编辑工具里我们常用的ctrl+F是一样的,也就是说:
正则表达式:'cat'
匹配:'cat', 'Cat', 'cAt', 'CAt', 'caT', 'CaT', 'cAT', 'CAT'
为了方便,下面的叙述中字符串和正则表达式的''都省略不写。
1.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')      %用'end'指定输出o2为匹配正则表达式的子串的结束位置
o3=regexpi(str,pat,'match')      %用'match'指定输出o3为匹配正则表达式的子串            
=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'
1.2      方括号符号
——匹配方括号中的任意一个。
为了解决句点符号匹配范围过于广泛这一问题,你可以在方括号([])里面指定看来有意义的字符。此时,只有方括号里面指定的字符才参与匹配。也就是说,正则表达式tn只匹配tan,Ten,tin和toN等。但Tmn,taen不匹配,因为在方括号之内你只能匹配单个字符。
matlab 例子程序:
clear;clc
str='ten,&8yn2tin6ui>&ton, t n,-356tpn,$$$$t#n,4@).,t@nT&nY';
pat='tn';         
=regexpi(str,pat,'start','end','match')%&Iacute;&Ecirc;±&Ecirc;&auml;&sup3;&ouml;&AElig;&eth;&Ecirc;&frac14;&Icirc;&raquo;&Ouml;&Atilde;&ordm;&Iacute;×&Oacute;&acute;&reg;
o11 =   1    10    18
o22 =   3    12    20
o33 =    'ten'    'tin'    'ton'
1.3      方括号中的连接符
'' ——匹配从字符c1开始到字符c2结束的字母序列(按字母表中的顺序)中的任意一个。
如匹配a,b,c,A,B,C即:正则表达式:tn ,匹配: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='tn';            
=regexpi(str,pat,'start','end','match')
o11 =   1    10    18    31
o22 =   3    12    20    33
o33 =   'ten'    'tin'    'ton'    'tpn'
1.4 特殊字符
\.等 ——就是由'\'引导的,代表有特殊意义或不能直接输入的单个字符。在使用fprintf函数输出时我们常用'\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.i.$.a';
pat1='.';pat2='\.';
o=regexpi(str,pat1,'match')
o1=regexpi(str,pat2,'match')

输出为:
o =    'l'    '.'    '['    'a'    '-'    'c'    ']'    'i'    '.'    '$'    '.'    'a'
o1 =    '.'    '.'    '.'
1.4      类表达式
\w,\s和\d等——匹配某一类字符中的一个
和上面的\n等表中的转义字符有所不同,\w,\s,\d等匹配的不是某个特定的字符,而是某一类字符。具体说明如下:
\w匹配任意的单个文字字符,相当于;
\s匹配任意的单个空白字符,相当于[\t\f\n\r];
\d匹配任意单个数字,相当于;
\S匹配除空白符以外的任意单个字符,相当于[^\t\f\n\r]——方括号中的^表示取反;
\W匹配任意单个字符,相当于[^a-zA-Z0-9_];
\D匹配除数字字符外的任意单个字符,相当于[^0-9]。
matlab程序例子:
s='This city has a population of more than 1,000,000.';
ptn='\d';
regexp(s,ptn,'match')

输出:
ans =   '1'    '0'    '0'    '0'    '0'    '0'    '0'
2 字符串的匹配
2.1 多次匹配
比如,我们要匹配'ppp',那么就可以用正则表达式'ppp',还有一种更简单一点的记法'p{3}'。正则表达式中的'{}'用来表示匹配前面的表达式的出现次数。就是说,'p{2,3}',匹配'pp'和'ppp'。除了'{}',还有几个字符,用在表示单个字符的正则表达式后面表示次数,如下所述。
expr? 与expr匹配的元素出现0或1次,相当于{0,1}
expr* 与expr匹配的元素出现0次或更多,相当于{0,}
expr+ 与expr匹配的元素出现1次或更多,相当于{1,}
expr{n} 与expr匹配的元素出现n次,相当于{n,n}
expr{n,} 与expr匹配的元素至少出现n次
expr{n,m} 与expr匹配的元素出现n次但不多于m次
假设我们要在文本文件中搜索美国的社会安全号码。这个号码的格式是999-99-9999。用来匹配它的正则表达式为{3}\-{2}\-{4}。在正则表达式中,连字符(“-”)有着特殊的意义,因此,它的前面要加上一个转义字符“\”。
如果希望连字符号可以出现,也可以不出现——即999-99-9999和999999999都属于正确的格式。这时,你可以在连字符号后面加上“?”数量限定符。这样正则表达式为{3}\-?{2}\-?{4}
另外,当我们使用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*匹配的字符子串的最末端,然后从那里开始再检查下一个字符与后面的表达式是否匹配,如果匹配就继续向前(如果一直成功则返回最长的字符串),如果不匹配则直接返回空。例如:
>>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.2逻辑运算符
exp|exp2 表示或者满足exp或者满足exp2
(expr) 将expr标记为一组、匹配expr,并将匹配的字符子串标记起来以供后面使用。——关于这部分内容下面还会有更详细介绍。
(?:expr) 说明expr为一组,相当于数学表达式中的()
例如:
lstr='A body or collection of such stories';
regexp(lstr,'(?:[^aeiou]){2,}','match')
ans =    'tori'
上面的表达式中{2,}对[^aeiou]起作用,如果去掉分组,则只对起作用,如下所示:
>>regexp(lstr,'[^aeiou]{2,}','match')
ans =    'tio'    'rie'
(?>expr) expr中的每个元素是一个分组
(?#expr) 放在(?#和)之间的是注释。如:
>>regexp(lstr, '(?# Match words in caps)\w*', 'match')
ans =    'A'
expr1|expr2 匹配两者之一即可,expr1或者expr2
>>regexp(lstr, '[^aeiou\s]o|[^aeiou\s]i', 'match')
ans =    'bo'    'co'    'ti'    'to'    'ri'
^expr 匹配expr,并且出现在原字符串最前端的子串
expr$ 匹配expr,并且出现在原字符串最末端的子串
>>pi(lstr, '^a\w*|\w*s$', 'match')
ans =    'A'    'stories'
\<expr 匹配expr,并且出现在一个单词最前端的子串
>> regexpi(lstr, '\<s\w*', 'match')
ans =    'such'    'stories'
expr\> 匹配expr,并且出现在一个单词最末端的子串
>> regexpi(lstr, '\w*tion\>', 'match')
ans =    'collection'
\<expr\> 更严格的单词匹配,如:以s开头,并且以h结尾的单词
>>regexpi(lstr, '\<s\w*h\>', 'match')
ans =    'such'
2.3.左顾右盼——利用上下文匹配
利用上下文的匹配来找到我们要找的内容。
expr1(?=expr2) 找到匹配expr1的子串,如果其后的字符串也匹配expr2
如下面的例子查找所有在','之前的单词。
s='Grammar Of, relating to, or being a noun or pronoun case that indicates possession.';
ptn='\w*(?=,)';
regexp(s,ptn,'match')
ans =    'Of'    'to'

expr1(?!expr2) 找到匹配expr1的子串如果其后的字符串不匹配expr2
下面的例子匹配所有不在','之前的单词
>>regexpi(s, '\w*(?!=,)', 'match')
ans =
    'Grammar'    'Of'    'relating'    'to'    'or'    'being'    'a'    'noun'    'or'    'pronoun'    'case'    'that'    'indicates'    'possession'
(?<=expr1)expr2 找到匹配expr2的子串,如果其前面的字符串也匹配expr1
下面的例子查找所有在','之后的单词,注意:','之后可能有空格
>>regexpi(s,'(?<=,\s*)\w*','match')
ans =   'relating'    'or'
(?<!expr1)expr2 找到匹配expr2的子串,如果其后的字符串不匹配expr1
下面的例子查找所有不在','之后的单词,
>>regexpi(s,'(?<!,\s*)\w*','match')
ans =
    'Grammar'    'Of'    'elating'    'to'    'r'    'being'    'a'    'noun'    'or'    'pronoun'    'case'    'that'    'indicates'    'possession'
3 标记(tokens)
这部分是比较难的一部分,但是应用得当可以实现非常强大的功能。
3.1 什么是标记(tokens)?
任何的正则表达式都可以用圆括号括起来作为一个标记。例如,创建一个记录钱数的标记,就可以用($\d+)。这样与之匹配的字符串就会被记录下来,根据这个标记出现的顺序,可以使用\n来引用匹配这个标记的字符串。如\3来引用与标记相匹配的第三个字符串。(如果在替换函数regexprep中,需要用 $3来引用。)
下面是一个例子,\S查找任意的非空白字符,\1用来说明要匹配第一个tokens的内容,也就是要立即再次查找刚刚匹配到的同一个字符,并且要紧挨着第一个。'tokens'选项用来向tok输出所有匹配到的标记;而'tokenExtents'则用来表示匹配标记的起始位置。
s='Grammar Of, relating to, or being a noun or pronoun case that indicates possession.';
=regexpi(s, '(\S)\1','match','tokens','tokenExtents')
>>mat
mat =   'mm'    'ss'    'ss'
>>tok{:}
ans =   'm'
ans =   's'
ans =   's'
>>ext{:}
ans =   4   4
ans =    75    75
ans =    78    78
3.2 如何使用标记?
(expr) 记录所有匹配表达式的字符,并做为一个标记,以备后面使用。如上面的例子,利用标记实现查找连续的重复字母。
\N匹配同一条正则表达式里的第N个标记中的字符串。如\1匹配第一个标记;
一个例子,用来查找html语句中类似<a>abc</a>的部分:
   hstr = '<!comment><tr nam="7507"></tr><table>Default</table><br>';
   expr = '<(\w+).*?>.*?</\1>';
    = 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';
>> = 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,则没有与之匹配的结果。
>> = regexp('Mr. Clark went to see her son', expr, 'match', 'tokens')
mat =                   {}
tok =                   {}
   

4 多行字符串与多正则表达式
4.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{:}
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
4.2 多个字符串与多个正则表达式匹配
这种情况下,应该满足字符串元胞数组中字符串的个数和正则表达式的个数相等——但维数不一定要相等——如可以用4*1的元胞数组与1*4的正则表达式相匹配。
expr = {'i\s', 'hou', '(.)\1', '\<w'};
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


4.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.
5 实践应用
1. 问题:查找包含某个字串的串。例如:
在str = {'apple_food' , 'chocolates_food', 'ipod_electronics', 'dvd_player_electronics', 'water_melon_food'} 中查找字串'food',得到结果 .
str = {'apple_food' , 'chocolates_food', 'ipod_electronics', 'dvd_player_electronics', 'water_melon_food'} ;
ptn='food';
m1=regexp(str,ptn,'match');
ix=~cellfun('isempty',m1);

2. 问题:如何将matlab中的^转换成C语言呢?如a^b转换成a**b,或者pow(a,b)。以下式为例s=1/2*w/(1+Pf^2*Pc-Pf^2*Pc*w1-w1*Pf^2-Pf*Pc-Pf^2*w^2+2*w1*Pf-2*Pf)
(matlab提供了ccode命令用于将matlab转换为c,这里仅为一例)
s='1/2*w/(1+Pf^2*Pc-Pf^2*Pc*w1-w1*Pf^2-Pf*Pc-Pf^2*w^2+2*w1*Pf-2*Pf)';
ptn='(\w{1,2})\^(\d{1})';
regexp(s,ptn,'tokens');
s1=regexprep(s,ptn,['pow(','$1',',','$2',')'])

3. 问题:删掉<和/>和它们之间的部分,例如:
处理前:Hello <a href="world">world</a>. 2 < 5
处理后:Hello world. 2 < 5
ss='Hello <a href="world">world</a>. 2 < 5';
b='<.*?>';
sr=regexprep(ss,b,'')

4. 问题:游程平滑算法:将连续的且个数小于某个阈值的0全部替换成1,例如:
平滑前:1111100000111100011
平滑后:1111100000111111111

a = ;
T = 4;
b = sprintf('%d',a);
b1 = regexprep(b,'(?<!0)0{1,3}(?!0)', repmat('1', size('$0')));
a1=b1-48


[ 本帖最后由 sogooda 于 2009-4-7 23:03 编辑 ]
页: [1]
查看完整版本: 浅说matlab的正则表达式