删除多个用空格分隔的连续单词

时间:2018-07-06 05:42:03

标签: regex perl

在模式/ man /下的代码中,连续匹配两次。因此,当我替换该模式时,只有第一个匹配项被匹配,而第二个匹配项不匹配。

据我了解的问题,第一个模式本身会一直匹配到第二个模式的开始(即人之后的空格是第一个模式的结束,也是第一个模式的开始)。因此第二个模式不匹配。连续发生此模式时如何全局匹配。

use strict;
use warnings;

#my $name =" man sky man ";  #this works

my $name =" man man sky";    #this does'nt
$name =~s/ man / nam /g;    #expected= 'nam nam sky'
print $name,"\n";

2 个答案:

答案 0 :(得分:5)

正则表达式正在消耗与其匹配的字符。因此,为避免这种情况,在这种情况下,应使用先行和后方匹配。选中perlre

$name =~ s/(?<=\s)man(?=\s)/nam/g;

引用perlre

向前看:

(?=pattern)
A zero-width positive lookahead assertion. For example, /\w+(?=\t)/ matches 
a word followed by a tab, without including the tab in $&.

向后看:

(?<=pattern) \K A zero-width positive lookbehind assertion. For
example, /(?<=\t)\w+/ matches a word that follows a tab, without
including the tab in $& . Works only for fixed-width lookbehind.

答案 1 :(得分:2)

我知道您想在空白字符或字符串的开头/结尾之间替换man

在这种情况下,您可以使用两种方法,正向查找包含对字符串边界和/或空格进行交替运算符检查,或负向查找包含在搜索词两端的非空白字符查找。

使用以下两种之一:

$name =~ s/(?<=^|\s)man(?=\z|\s)/nam/g;
$name =~ s/(?<!\S)man(?!\S)/nam/g;

从效率的角度来看,第二种方法更好,因为轮换有点“昂贵”。

后面的(?<=^|\s)正向匹配字符串中的位置,该位置的前面是字符串(^或(|)空格(\s)和{ {1}}正向超前确保在(?=$|\s)之后紧跟空白或字符串结尾($)。

后面的man否定性匹配字符串中不立即带有非空白字符的位置,即,如果存在非空白字符,则不存在匹配项),并且(?<!\S)否定前瞻断言(?!\S)之后没有非空格。

查看有关Lookaround Assertions at perlre的更多详细信息。