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

Regex 删除多个用空格分隔的连续单词,regex,perl,Regex,Perl,在下面的代码中,模式/man/连续匹配两次。因此,当我替换该模式时,只有第一次出现的匹配,但第二次出现的不匹配 正如我所理解的问题,第一个模式本身匹配到第二个模式的开始(即,人之后的空间是第一个模式的结束,也是第一个模式的开始)。所以第二种模式不匹配。如何在连续出现时全局匹配此模式 use strict; use warnings; #my $name =" man sky man "; #this works my $name =" man man sky"; #this does

在下面的代码中,模式
/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";

正则表达式正在消耗它匹配的字符。所以,为了避免这种情况,在这种情况下应该使用lookahead和lookback来匹配它。检查

回头看:


(?我知道您想在空白字符或字符串的开始/结束之间替换
man

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

使用以下两种方法之一:

$name =~ s/(?<=^|\s)man(?=\z|\s)/nam/g;
$name =~ s/(?<!\S)man(?!\S)/nam/g;
$name=~s/(?
从效率的角度来看,第二种选择更好,因为替代有点“昂贵”

(?(?!\S)
负先行断言在
man
之后没有非空格


查看有关的更多详细信息。

因此,
“man-man-sky”
应该导致
“man-nam sky”
,对吗?请精确回答这个问题。这看起来像是XY问题。如果要匹配整个单词,请使用
\b
断言。因此,
“man-man-man-sky”
应该导致
“man-nam sky”
,对吗?请精确地回答这个问题。
man-man-sky
应该变成
nam-nam-sky
,然后你应该使用(参见)。更有效:
s/man(?=)/nam/g
s/\Kman(?=\s)/nam/g
(?=\n?\z)
,因此
(?=$\124s)
意味着
(?=\n?\z)
,这是一种复杂的编写
(?=\s|\z)
请注意,您的替换几乎与
s/\bman\b/nam/g
相同,这对于OP来说可能已经足够接近了。@ikegami如果目标是在空格或字符串的最后匹配,那么应该使用
\z
chomp
可以缓解这个问题。)
(?!\S)和
(?!\S)
环视词定义了空格边界而不是单词边界,因此尽管它们看起来相似,但它们却大不相同:
\bman\b
匹配
战争之人中的
人,但是
(?.Re“如果目标是”,则不会,
(?=$)\S)
(?=\s |\z)
就像我说的那样是等价的……但仍然不同
(?=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.
$name =~ s/(?<=^|\s)man(?=\z|\s)/nam/g;
$name =~ s/(?<!\S)man(?!\S)/nam/g;