在perl regex中,仅替换一行中第二次出现的string

sqougxex  于 2022-11-15  发布在  Perl
关注(0)|答案(4)|浏览(183)

我有一个类似"ven|ven|vett|vejj|ven|ven"的字符串。将每个"|"分隔符视为每列。
通过使用"|"拆分字符串,保存数组中的所有列,并将每列读入$str
所以,我试着把它当作

$string =~ s/$str/venky/g if $str =~ /ven/i; # it will do globally.

不符合要求。
根据需要,我需要在字符串出现的特定次数处替换字符串。
例如,我请求将第二次出现的"ven"更改为 venky
那我怎么能简单地满足这个要求呢?是不是像

$string =~ s/ven/venky/2;

据我所知,我们有'o'表示替换一次,'g'表示全局。我正在努力寻找解决方案,以获得特定事件的替换。我不应该使用pos()来获得位置,因为字符串不断变化。这变得很难跟踪它的每一次。这是我的意图。
请在这方面帮助我。

yhxst69z

yhxst69z1#

没有可以添加到正则表达式中的标志来执行此操作。
最简单的方法是拆分和循环。然而,如果你坚持使用一个正则表达式,这是可行的:

/^(?:[^v]|v[^e]|ve[^n])*ven(?:[^v]|v[^e]|ve[^n])*\Kven/

如果要替换第N个匹配项而不是第二个匹配项,可以执行以下操作:

/^(?:(?:[^v]|v[^e]|ve[^n])*ven){N-1}(?:[^v]|v[^e]|ve[^n])*\Kven/

总体思路:
(?:[^v]|v[^e]|ve[^n])*-匹配任何不属于ven的字符串
\K是一个很酷的匹配器,它可以丢弃目前为止匹配的所有内容,因此您可以将其用作可变长度的lookbehind

mw3dktmi

mw3dktmi2#

目前,如果字符串中包含ven的匹配项,则用“venky”替换“ven”的每个示例,当然,它确实包含ven
我假设你要做的是在字符串中用'ven'替换'venky',如果它是第二个元素:

my $string = 'ven|ven|vett|vejj|ven|ven';

my @elements = split(/\|/, $string);

my $count;
foreach (@elements){
    $count++;
    s/$_/venky/g if /ven/i and $count == 2;
}

print join('|', @elements);
print "\n";
szqfcxe2

szqfcxe23#

你的方法已经很好了,你说的有道理,但是我觉得你在执行上有困难。
我创建了一个函数来完成这项工作,它有4个参数:

  • $string是我们要处理的字符串
  • $n是要替换的第 * n * 个示例
  • $needle是您要替换的东西--东西 * 大海捞针 *

请注意,现在我们允许传递可能包含正则表达式的内容。

  • $replacement$needle的替代

其思想是将字符串拆分,然后检查每个元素是否与模式($needle)匹配,并跟踪有多少个元素匹配。如果达到了第n个,则替换它并停止处理。然后将字符串重新组合在一起。

use strict;
use warnings;
use feature 'say';

say replace_nth_occurance("ven|ven|vett|vejj|ven|ven", 2, 'ven', 'venky');

sub replace_nth_occurance {
  my ($string, $n, $needle, $replacement) = @_;

  # take the string appart
  my @elements = split /\|/, $string;

  my $count = 0; # keep track of ...
  foreach my $e (@elements) {
    $count++ if $e =~ m/$needle/;    # ... how many matches we've found
    if ($count == $n) {
      $e =~ s/$needle/$replacement/; # replace
      last;                          # and stop processing
    }
  }

  # put it back into the pipe-separated format
  return join '|', @elements;
}

输出

ven|venky|vett|vejj|ven|ven
t98cgbkg

t98cgbkg4#

将第n次出现的“ven”替换为“venky”:

my $n = 3;
my $test = "seven given ravens";
$test =~ s/ven/--$n == 0 ? "venky" : $&/eg;

这会使用具有/e旗标的功能,将替代部分指定为运算式。

相关问题