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

在日常工作中,你可能会遇到这种情况,你只能用正则表达式(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语言的正则表达式,就不用这么麻烦了,只用“?!”就可以了。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值