摘
关
1.
正则表达式就是一个表达式(也是一串字符),它定义了某种字符串模式——利用正则表达式,可以
对大段的文字进行复杂的查找、替换等。本文将以 Matlab 为编程语言,讲解正则表达式的概念和使用方法,
并将在文末以实例说明正则表达式的实践应用。
Matlab 提供的正则表达式函数有三个:
regexp——用于对字符串进行查找,大小写敏感;
regexpi——用于对字符串进行查找,大小写不敏感;
regexprep——用于对字符串进行查找并替换。
简要介绍一下这三个函数,以 regexpi 为例
用法 1:
[start end extents match tokens names] = regexpi('str', 'expr')
start 为匹配字符串的起始位置;end 为匹配字符串的终止位置;extents 为扩展内容,和'tokens'指示符
一起用,指示出现 tokens 的位置;match 即找到的匹配字串;tokens 匹配正则表达式中标记(tokens)的字串;
names 为匹配到的命名标记的标记名。
用法 2:
若不需要所有的输出,可以用下面的方式有选择的输出。
[v1 v2 ...] = regexpi('str', 'expr', 'q1', 'q2', ...)
'q1'、'q2' ......
v2......
2.
我们先从简单的开始
的正则表达式就是
'Cat'、'cAt'、'CAt'、'caT'、'CaT'、'cAT'、'CAT'。
为了方便,下面的叙述中字符串和正则表达式的''都省略不写。
2.1
.
假设你在玩英文拼字游戏,想要找出三个字母的单词,而且这些单词必须以
Matlab 程序实例:
clear;clc
str='ten,&8yn2tin6ui>&ton, t n,-356tpn,$$$$t#n,4@).,t@nT&nY';
pat='t.n';
o1=regexpi(str,pat,'start')
o2=regexpi(str,pat,'end')
o3=regexpi(str,pat,'match')
[o11,o22,o33]=regexpi(str,pat,'start','end','match')
输出为:
o1 =
o2 =
o3 =
o11 =
o22 =
o33 =
2.2
[oum]
为了解决句点符号匹配范围过于广泛这一问题,你可以在方括号([])里面指定看来有意义的字符。此时,只有方括号里面指定的字符才参与匹配。也就是说,正则表达式 t[aeio]n 只匹配 tan、Ten、tin 和 toN等。但 Tmn、taen 不匹配,因为在方括号之内你只能匹配单个字符。
Matlab 程序实例:
clear;clc
str='ten,&8yn2tin6ui>&ton, t n,-356tpn,$$$$t#n,4@).,t@nT&nY';
pat='t[aeiou]n';
[o11,o22,o33]=regexpi(str,pat,'start','end','match')
o11 =
o22 =
o33 =
2.3
'[c1-c2]'
Matlab 程序实例:
clear;clc
str='ten,&8yn2tin6ui>&ton, t n,-356tpn,$$$$t#n,4@).,t@nT&nY';
pat='t[a-z]n';
[o11,o22,o33]=regexpi(str,pat,'start','end','match')
o11 =
o22 =
o33 =
2.4
.等
在使用 fprintf 函数输出时我们常用
下面是一些匹配单个字符的转义字符正则表达式及所匹配的值。
xN 或x{N}
oN 或o{N}
a
b
t
n
v
f
r
e
c
Matlab 程序实例:
clear;clc
str='l.[a-c]i.$.a';
pat1='.';pat2='.';
o=regexpi(str,pat1,'match')
o1=regexpi(str,pat2,'match')
输出为:
o =
o1 =
2.5
w、s
和上面的
w
s
d
S
W
D
Matlab 程序实例:
s='This city has a population of more than 1,000,000.';
ptn='d';
regexp(s,ptn,'match')
输出为:
ans =
3.字符串的匹配
3.1
例如需要匹配
字符,用在表示单个字符的正则表达式后面表示次数,如下所述:
expr?
expr*
expr+
expr{n}
expr{n,}
expr{n,m}
假设我们要在文本文件中搜索美国的社会安全号码。这个号码的格式是 999-99-9999。用来匹配它的正则表达式为
如果希望连字符号可以出现,也可以不出现
>>str = '<tr valign=top><td><a name="19184"></a>xyz';
>>regexp(hstr, '<.*>', 'match')
ans =
如果我们希望匹配尽可能短的字符子串时,可以在上面我们使用的字符串后使用
例如:
>>str = '<tr valign=top><td><a name="19184"></a>xyz';
>>regexp(hstr, '<.*?>', 'match')
ans =
这个表达式的执行过程是这样的,先执行 expr*,“游标”(如果有的话)就指到了与
>>str = '<tr valign=top><td><a name="19184"></a>xyz';
>>regexp(hstr, '<.*+>', 'match')
ans =
>>regexp(hstr, '<.*+', 'match')
ans =
3.2
exp|exp2
(expr)
(?:expr)
例如:
lstr='A body or collection of such stories';
regexp(lstr,'(?:[^aeiou][aeiou]){2,}','match')
ans =
上面的表达式中
>>regexp(lstr,'[^aeiou][aeiou]{2,}','match')
ans =
(?>expr) expr 中的每个元素是一个分组。(?#expr)
>>regexp(lstr, '(?# Match words in caps)[A-Z]w*', 'match')
ans =
expr1|expr2
>>regexp(lstr, '[^aeious]o|[^aeious]i', 'match')
ans =
^expr
>>pi(lstr, '^aw*|w*s$', 'match')
ans =
<expr
>> regexpi(lstr, '<sw*', 'match')
ans =
expr>
>> regexpi(lstr, 'w*tion>', 'match')
ans =
<expr>
>>regexpi(lstr, '<sw*h>', 'match')
ans =
3.3
利用上下文的匹配来找到我们要找的内容。expr1(?=expr2)
s='Grammar Of, relating to, or being a noun or pronoun case that indicates possession.';
ptn='w*(?=,)';
regexp(s,ptn,'match')
ans =
expr1(?!expr2)
>>regexpi(s, 'w*(?!=,)', 'match')
ans=
(?<=expr1)expr2
>>regexpi(s,'(?<=,s*)w*','match')
ans =
(?<!expr1)expr2
>>regexpi(s,'(?<!,s*)w*','match')
ans=
4.标记(tokens)
这部分是比较难的一部分,但是应用得当可以实现非常强大的功能。
4.1
任何的正则表达式都可以用圆括号括起来作为一个标记。例如,创建一个记录钱数的标记,就可以用($d+)。这样与之匹配的字符串就会被记录下来,根据这个标记出现的顺序,可以使用
来引用。) 下面是一个例子,S 查找任意的非空白字符,1 用来说明要匹配第一个 tokens 的内容,也就是要立即再次查找刚刚匹配到的同一个字符,并且要紧挨着第一个。'tokens'
s='Grammar Of, relating to, or being a noun or pronoun case that indicates possession.';
[mat,tok,ext]=regexpi(s, '(S)1','match','tokens','tokenExtents')
>>mat
>>tok{:}
ans =
ans =
ans =
>>ext{:}
ans =
ans =
ans =
4.2
(expr)
N
>> mat{:}
ans =
ans =
>> tok{:}
ans =
ans =
$N
>> regexprep('Norma Jean Baker', '(w+sw+)s(w+)', '$2, $1')
ans =
(?<name>expr)
与名为 name 的标记相匹配。下面这个例子和这部分第一个例子是一样的,只不过使用了命名的标记。
>>poestr = ['While I nodded, nearly napping, ' ...
ans =
(?(tok)expr)
么后面就匹配
>>expr = 'Mr(s?)..*?(?(1)her|his) son';
>>[mat tok] = regexp('Mr. Clark went to see his son', expr, 'match', 'tokens')
tok =
>>tok{:}
ans =
如果把句子中的 his 改成 her,则没有与之匹配的结果。
>>[mat tok] = regexp('Mr. Clark went to see her son', expr, 'match', 'tokens')
mat =
tok =
5.多行字符串与多正则表达式
5.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 =
ans =
ans =
ans =
5.2
这种情况下,应该满足字符串元胞数组中字符串的个数和正则表达式的个数相等——但维数不一定要相等——如可以用 4*1 的元胞数组与 1*4 的正则表达式相匹配。
expr = {'is', 'hou', '(.)1', '<w[aeiou]'};
idx = regexpi(cstr, expr);
idx{:}
ans =
ans =
ans =
ans =
5.3
这个功能是在匹配的基础上,在正则表达式后面加入要替换的字符串即可。下面这个是 matlab 中的例子,很容易理解。
>>s = regexprep(cstr, '(.)1', '--', 'ignorecase')
s =
6.应用实例
问题 1:查找包含某个字串的串。例如:
在 str=
中查找字串'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 中的
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 = [1 0 0 1 0 0 0 0 1 1 1 1 1 0 0 0 0 0 1 1 1 1 0 0 0 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1];
T = 4;
b = sprintf('%d',a);
b1 = regexprep(b,'(?<!0)0{1,3}(?!0)', repmat('1', size('$0')));
a1=b1-48