您的位置:首页 > 其它

巧用多个正则表达式解决取反替换问题(解决不匹配则替换问题)——用sed和perl的正则表达式

2008-04-26 23:45 633 查看
在日常工作中,你可能会遇到这种情况,你只能用正则表达式(sed或perl的正则表达式)来解决这样一个问题:替换所有不匹配某表达式的输入成为某特殊字符串。特别是某些软件的配置选项只提供了让你使用正则表达式的情况。例如配置“除了某含有域名的URL可以访问外,不能访问其它URL”等策略。本文介绍一种在没有取反正则表达式情况下,如何用三次正则表达式解决这个问题。

典型的例子是电话呼叫策略配置的例子,如请配置“只允许拨打上海电话,不允许拨打任何其它地区电话”策略。实际上要求:被叫电话号码将作为表达式的输入,要求若号码不是以021为前缀,则必须把整个号码转换为字符串bar。如:

被叫号码若为 02188888888 则经处理后,输出还是 02188888888;而诸如02566666666之类所有不以021为前缀的电话号码都要被转化为bar字符串。处理过程只能是正则表达式,且允许多个表达式(前一个表达式的输出为后一个表达式的输入)。

我曾在网上查过,没有找到“不匹配则替换”的方法。我想的方法是用三个正则表达式解决。例子:

echo 02188888888 | sed 's/^/(.*/)$/_t_/1/' | sed 's/^_t_021/021/' | sed 's/^_t_.*$/bar/'

这里只是用Linux命令来与管道演示一下,命令执行的结果将输出02188888888(保持号码不变),步骤说明:

1)第一个表达式 sed 's/^/(.*/)$/_t_/1/' 意思是“在号码前面加一个特殊前缀_t_”,号码02188888888被处理后,第一个表达式将输出 _t_02188888888 。

2)第二个表达式 sed 's/^_t_021/021/' 意思是“若输入的字符串前缀为_t_021,则转化该前缀为021”,此处_t_02188888888 又变回了 02188888888。——感觉有点无聊把,但等会就知道这样做的用处了^_^

3)第三个表达式 sed 's/^_t_.*$/bar/' 意思是“若输入的字符串前缀为_t_,则把整个字符串替换成bar”,此处输入为02188888888,所以本表达式不起作用,最终输出还是02188888888。(即允许拨打该号码)

再看看若输入的是一个非021前缀的号码:

echo 05788888888 | sed 's/^/(.*/)$/_t_/1/' | sed 's/^_t_021/021/' | sed 's/^_t_.*$/bar/'

1)第一个表达式 sed 's/^/(.*/)$/_t_/1/' 处理结果在号码05788888888前加了前缀:_t_05788888888 。

2)第二个表达式 sed 's/^_t_021/021/' 发现字符串_t_05788888888 不是以_t_021为前缀,所以它将不做任何处理,输出的结果还是_t_05788888888 。

3)第三个表达式 sed 's/^_t_.*$/bar/' 发现字符串前缀为_t_,则把整个字符串替换成了bar。OK看明白了吗^_^

OK也许你已经发现,上述表达式只适用于“替换前缀不为XX的字符串”,若要匹配的标识在字符串中间怎么办?比如,如何实现“请替换不含hero的整个字符串为bar”的要求。其实对上面的表达式稍加处理就可以了:

echo 'I am hero yeah' | sed 's/^/(.*/)$/_t_/1/' | sed 's/^_t_/(.*/)hero//1hero/' | sed 's/^_t_.*$/bar/'

将输出 'I am hero yeah' ,而输入其它字符串,如:

echo 'He is not' | sed 's/^/(.*/)$/_t_/1/' | sed 's/^_t_/(.*/)hero//1hero/' | sed 's/^_t_.*$/bar/'

将输出 'bar'。

Perl表达式实现和sed差不多,只是 /(.*/) 之类的只用直接写成 (.*) 就行了。下面是一个测试演示用的perl脚本,大家能看到整个处理过程是怎么样的:

------------------------

#!/usr/bin/perl

sub parse {
my $str = shift;
print "input = /"$str/"/n";

$str =~ s/^(.*)$/_t_/1/;
print "s/^(.*)/$/_t_//1/ => /"$str/"/n";

$str =~ s/^_t_(.*)hero//1hero/;
print "s/^_t_(.*)hero///1hero/ => /"$str/"/n";

$str =~ s/^_t_.*$/bar/;
print "s/^_t_.*/$/bar/ => /"$str/"/n";

print "output = /"$str/"/n";
}

parse("Iamheroyeah");
print "/n";
parse("Heisnotagoodman");

-------------------------------------

用 perl test.pl 来查看 (test.pl为该文件名)输出结果为:

input = "Iamheroyeah"
s/^(.*)$/_t_/1/ => "_t_Iamheroyeah"
s/^_t_(.*)hero//1hero/ => "Iamheroyeah"
s/^_t_.*$/bar/ => "Iamheroyeah"
output = "Iamheroyeah"

input = "Heisnotagoodman"
s/^(.*)$/_t_/1/ => "_t_Heisnotagoodman"
s/^_t_(.*)hero//1hero/ => "_t_Heisnotagoodman"
s/^_t_.*$/bar/ => "bar"
output = "bar"

注:若是用java语言的正则表达式,就不用这么麻烦了,只用“?!”就可以了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: