用perl替换字符串中的多个实例

时间:2022-07-05 16:53:15

I have the following use case, input present in the file as:

我有以下用例,输入文件中的输入为:

Line1 : AA BB CC DD EE

I want to replace this with

我想替换它

1 2 3 4 5

Output

Line1: 1 2 3 4 5

In one regular expression in Perl, can I do this

在Perl中的一个正则表达式中,我可以这样做吗?

I was trying this but was unsucessful

我试过这个但是没有成功

my @arr1 = ("AA", "BB", "CC", "DD", "EE");
open F2, $file;
my $count = 0;
while (<F2>) {
    my $str = $_;
    $str =~ s/$arr[$count]/$count+1/g;
    print to file
}

close(F2);

This doesn't do the trick any ideas

这不是任何想法的伎俩

5 个解决方案

#1


If I understand correctly, you want to replace every word with number (incremented by 1 after every word). Here is program with tests:

如果我理解正确,你想用数字替换每个单词(每个单词后加1)。这是带测试的程序:

#!/usr/bin/perl

use strict;
use warnings;
use Test::More qw(no_plan);

sub replace {
  my $str=shift;
  my $count=1;
  $str=~s/\w+/$count++/ge;
  return $str;
}


is(replace('AA AA DD EE'),'1 2 3 4');
is(replace('A B C D E'),'1 2 3 4 5');

#2


You need to do something to modify the file in place, which you are not currently doing. The easiest option would be to use File::Inplace (or to output to a second file).

您需要做一些事情来修改您当前没有执行的文件。最简单的选择是使用File :: Inplace(或输出到第二个文件)。

Additionally you are not looping over the array, but over the lines on the file so it'll replace only $arr[0] for 1 on each line.

另外,你不是循环遍历数组,而是遍历文件中的行,因此它将在每行上仅替换$ arr [0]为1。

  use strict;
  use warnings;
  use File::Inplace;

  my @replacees = ("AA", "BB", "CC", "DD", "EE");
  my $editor = new File::Inplace(file => "file.txt", regex => "\n");
  while (my ($line) = $editor->next_line) {
    my $count = 1
    for my $replacee (@replacees) { 
        if ($line =~ m/$replacee/) {
            $line =~ s/$replacee/$count/g;
        }
        $count = $count + 1;
    }
    $editor->replace_line($line);
  }
  $editor->commit;

#3


As for writing to the same file, please note Vinko answer. As for replacing strings, please check this snippet:

至于写入同一个文件,请注意Vinko的答案。至于替换字符串,请检查以下代码段:

my @arr1 = ("AA", "BB", "CC", "DD", "EE");
my %replacements = map { ($arr1[$_] => $_ + 1) } (0..$#arr1);
my $regexp = join( '|', sort { length($b) <=> length($a) } @arr1);

open F2, $file;
while (<F2>) {
    my $str = $_;
    $str =~ s/($regexp)/$replacements{$1}/ge;
    print $str;
}
close(F2);

Important parts:

my %replacements = map { ($arr1[$_] => $_ + 1) } (0..$#arr1);

It builds hash with keys from @arr1, and values are the index of given value in @arr1 incremented by 1.

它使用@ arr1中的键构建哈希值,值是@ arr1中给定值的索引,加1。

For example, for @arr1 = ("a", "b", "d", "c"); %replacements will be: ("a" => 1, "b", => 2, "c" => 4, "d" => 3);

例如,对于@ arr1 =(“a”,“b”,“d”,“c”); %替换将是:(“a”=> 1,“b”,=> 2,“c”=> 4,“d”=> 3);

my $regexp = join( '|', sort { length($b) <=> length($a) } @arr1);

This builds base regexp for finding all words from @arr1. The sort part orders words by their length descending. So, for @arr1 = ("a", "ba", "bac") $regexp will be 'bac|ba|a'.

这构建了基本正则表达式,用于查找@ arr1中的所有单词。排序部分按其长度递减来排序单词。所以,对于@ arr1 =(“a”,“ba”,“bac”),$ regexp将是'bac | ba | a'。

This ordering is important as otherwise there would be problems if any of the words would be prefix of any other word (as with "ba" and "bac" in my example).

这种排序很重要,否则如果任何单词都是任何其他单词的前缀(如我的例子中的“ba”和“bac”)则会出现问题。

As a last word, usage of filehandles as FH is rather discouraged, as these are globals, and generate "interesting" problems in more complex programs. Instead use open like this:

换句话说,文件句柄作为FH的使用是相当不鼓励的,因为它们是全局的,并且在更复杂的程序中产生“有趣”的问题。而是像这样使用open:

open my $fh, 'filename';

or better yet:

或者更好的是:

open my $fh, '<', 'filename';

#4


First, a correction:

一,修正:

while (<F2>) {
    my $str = $_;

If you want the line read to end up in $str, there is no reason to involve $_ in the process:

如果您希望读取的行以$ str结尾,则没有理由在此过程中涉及$ _:

while ( my $str = ) {

while(my $ str =){

which also brings up the point made by depesz that you should use lexical filehandles rather than package global bareword filehandles.

这也提出了由depesz提出的观点,你应该使用词法文件句柄而不是打包全局裸字文件句柄。

Now, looking at your loop:

现在,看看你的循环:

my $count = 0;
while (my $str = <$input_fh>) {
    $str =~ s/$arr[$count]/$count+1/g;
    # ...
}

there seems to be an implicit assumption that there cannot be more lines in the file than the number of elements in @foo. In which case, you need not use $count: $. would do just fine. Say you are on the second line. Your code says you want to replace all occurrences of BB on that line with 2 which is different than what you describe verbally.

似乎有一个隐含的假设,即文件中的行数不能超过@foo中的元素数。在这种情况下,您不需要使用$ count:$。会做得很好。假设你在第二行。您的代码表示您希望将该行上出现的所有BB替换为2,这与您口头描述的不同。

This is an important point: Any code you post ought to be consistent with the verbal description.

这一点非常重要:您发布的任何代码都应与口头描述保持一致。

Anyway, here is one way:

无论如何,这是一种方式:

rty.pl

#!/usr/bin/perl

use strict;
use warnings;

use File::Slurp;

my ($input) = @ARGV;

write_file(
    $input, [
        map { s/( ([A-Z]) \2 )/ord($2) - ord('A') + 1/gex; $_ } read_file $input
    ]
);
__END__

test.data:

Line1 : AA BB CC DD EE
Line1 : AA BB CC DD EE
Line1 : AA BB CC DD EE
Line1 : AA BB CC DD EE

$ rty.pl test.data

test.data after script invocation:

脚本调用后的test.data:

Line1 : 1 2 3 4 5
Line1 : 1 2 3 4 5
Line1 : 1 2 3 4 5
Line1 : 1 2 3 4 5

#5


Either way it will work

无论哪种方式它都会起作用

my %arr2 = ('AA'=>1, 'BB'=>2,'CC'=>3,'DD'=>4,'EE'=>5,'FF'=>6);

我的%arr2 =('AA'=> 1,'BB'=> 2,'CC'=> 3,'DD'=> 4,'EE'=> 5,'FF'=> 6);

open F2, "t1.txt";
open F3, ">out.txt";
while () {
      my $str = $;
      print F3 join ' ' ,map {s/$
/$arr2{$}/g; $} split / /,$str;
      print F3 "\n";
}

打开F2,“t1.txt”;打开F3,“> out.txt”; while(){my $ str = $; print F3 join'',map {s / $ / $ arr2 {$} / g; $} split / /,$ str;打印F3“\ n”; }

close(F2);
close(F3);

or

my @arr1 = ("AA", "BB", "CC", "DD", "EE","FF");
my %hashArr = map { ($arr1[$] => $ + 1) } (0..$#arr1);

my @ arr1 =(“AA”,“BB”,“CC”,“DD”,“EE”,“FF”);我的%hashArr = map {($ arr1 [$] => $ + 1)}(0 .. $#arr1);

open F2, "t1.txt";
open F3, ">out.txt";
while () {
      my $str = $;
      print F3 join ' ' ,map {s/$
/$hashArr{$}/g; $} split / /,$str;
      print F3 "\n";
}

打开F2,“t1.txt”;打开F3,“> out.txt”; while(){my $ str = $; print F3 join'',map {s / $ / $ hashArr {$} / g; $} split / /,$ str;打印F3“\ n”; }

close(F2);
close(F3);

#1


If I understand correctly, you want to replace every word with number (incremented by 1 after every word). Here is program with tests:

如果我理解正确,你想用数字替换每个单词(每个单词后加1)。这是带测试的程序:

#!/usr/bin/perl

use strict;
use warnings;
use Test::More qw(no_plan);

sub replace {
  my $str=shift;
  my $count=1;
  $str=~s/\w+/$count++/ge;
  return $str;
}


is(replace('AA AA DD EE'),'1 2 3 4');
is(replace('A B C D E'),'1 2 3 4 5');

#2


You need to do something to modify the file in place, which you are not currently doing. The easiest option would be to use File::Inplace (or to output to a second file).

您需要做一些事情来修改您当前没有执行的文件。最简单的选择是使用File :: Inplace(或输出到第二个文件)。

Additionally you are not looping over the array, but over the lines on the file so it'll replace only $arr[0] for 1 on each line.

另外,你不是循环遍历数组,而是遍历文件中的行,因此它将在每行上仅替换$ arr [0]为1。

  use strict;
  use warnings;
  use File::Inplace;

  my @replacees = ("AA", "BB", "CC", "DD", "EE");
  my $editor = new File::Inplace(file => "file.txt", regex => "\n");
  while (my ($line) = $editor->next_line) {
    my $count = 1
    for my $replacee (@replacees) { 
        if ($line =~ m/$replacee/) {
            $line =~ s/$replacee/$count/g;
        }
        $count = $count + 1;
    }
    $editor->replace_line($line);
  }
  $editor->commit;

#3


As for writing to the same file, please note Vinko answer. As for replacing strings, please check this snippet:

至于写入同一个文件,请注意Vinko的答案。至于替换字符串,请检查以下代码段:

my @arr1 = ("AA", "BB", "CC", "DD", "EE");
my %replacements = map { ($arr1[$_] => $_ + 1) } (0..$#arr1);
my $regexp = join( '|', sort { length($b) <=> length($a) } @arr1);

open F2, $file;
while (<F2>) {
    my $str = $_;
    $str =~ s/($regexp)/$replacements{$1}/ge;
    print $str;
}
close(F2);

Important parts:

my %replacements = map { ($arr1[$_] => $_ + 1) } (0..$#arr1);

It builds hash with keys from @arr1, and values are the index of given value in @arr1 incremented by 1.

它使用@ arr1中的键构建哈希值,值是@ arr1中给定值的索引,加1。

For example, for @arr1 = ("a", "b", "d", "c"); %replacements will be: ("a" => 1, "b", => 2, "c" => 4, "d" => 3);

例如,对于@ arr1 =(“a”,“b”,“d”,“c”); %替换将是:(“a”=> 1,“b”,=> 2,“c”=> 4,“d”=> 3);

my $regexp = join( '|', sort { length($b) <=> length($a) } @arr1);

This builds base regexp for finding all words from @arr1. The sort part orders words by their length descending. So, for @arr1 = ("a", "ba", "bac") $regexp will be 'bac|ba|a'.

这构建了基本正则表达式,用于查找@ arr1中的所有单词。排序部分按其长度递减来排序单词。所以,对于@ arr1 =(“a”,“ba”,“bac”),$ regexp将是'bac | ba | a'。

This ordering is important as otherwise there would be problems if any of the words would be prefix of any other word (as with "ba" and "bac" in my example).

这种排序很重要,否则如果任何单词都是任何其他单词的前缀(如我的例子中的“ba”和“bac”)则会出现问题。

As a last word, usage of filehandles as FH is rather discouraged, as these are globals, and generate "interesting" problems in more complex programs. Instead use open like this:

换句话说,文件句柄作为FH的使用是相当不鼓励的,因为它们是全局的,并且在更复杂的程序中产生“有趣”的问题。而是像这样使用open:

open my $fh, 'filename';

or better yet:

或者更好的是:

open my $fh, '<', 'filename';

#4


First, a correction:

一,修正:

while (<F2>) {
    my $str = $_;

If you want the line read to end up in $str, there is no reason to involve $_ in the process:

如果您希望读取的行以$ str结尾,则没有理由在此过程中涉及$ _:

while ( my $str = ) {

while(my $ str =){

which also brings up the point made by depesz that you should use lexical filehandles rather than package global bareword filehandles.

这也提出了由depesz提出的观点,你应该使用词法文件句柄而不是打包全局裸字文件句柄。

Now, looking at your loop:

现在,看看你的循环:

my $count = 0;
while (my $str = <$input_fh>) {
    $str =~ s/$arr[$count]/$count+1/g;
    # ...
}

there seems to be an implicit assumption that there cannot be more lines in the file than the number of elements in @foo. In which case, you need not use $count: $. would do just fine. Say you are on the second line. Your code says you want to replace all occurrences of BB on that line with 2 which is different than what you describe verbally.

似乎有一个隐含的假设,即文件中的行数不能超过@foo中的元素数。在这种情况下,您不需要使用$ count:$。会做得很好。假设你在第二行。您的代码表示您希望将该行上出现的所有BB替换为2,这与您口头描述的不同。

This is an important point: Any code you post ought to be consistent with the verbal description.

这一点非常重要:您发布的任何代码都应与口头描述保持一致。

Anyway, here is one way:

无论如何,这是一种方式:

rty.pl

#!/usr/bin/perl

use strict;
use warnings;

use File::Slurp;

my ($input) = @ARGV;

write_file(
    $input, [
        map { s/( ([A-Z]) \2 )/ord($2) - ord('A') + 1/gex; $_ } read_file $input
    ]
);
__END__

test.data:

Line1 : AA BB CC DD EE
Line1 : AA BB CC DD EE
Line1 : AA BB CC DD EE
Line1 : AA BB CC DD EE

$ rty.pl test.data

test.data after script invocation:

脚本调用后的test.data:

Line1 : 1 2 3 4 5
Line1 : 1 2 3 4 5
Line1 : 1 2 3 4 5
Line1 : 1 2 3 4 5

#5


Either way it will work

无论哪种方式它都会起作用

my %arr2 = ('AA'=>1, 'BB'=>2,'CC'=>3,'DD'=>4,'EE'=>5,'FF'=>6);

我的%arr2 =('AA'=> 1,'BB'=> 2,'CC'=> 3,'DD'=> 4,'EE'=> 5,'FF'=> 6);

open F2, "t1.txt";
open F3, ">out.txt";
while () {
      my $str = $;
      print F3 join ' ' ,map {s/$
/$arr2{$}/g; $} split / /,$str;
      print F3 "\n";
}

打开F2,“t1.txt”;打开F3,“> out.txt”; while(){my $ str = $; print F3 join'',map {s / $ / $ arr2 {$} / g; $} split / /,$ str;打印F3“\ n”; }

close(F2);
close(F3);

or

my @arr1 = ("AA", "BB", "CC", "DD", "EE","FF");
my %hashArr = map { ($arr1[$] => $ + 1) } (0..$#arr1);

my @ arr1 =(“AA”,“BB”,“CC”,“DD”,“EE”,“FF”);我的%hashArr = map {($ arr1 [$] => $ + 1)}(0 .. $#arr1);

open F2, "t1.txt";
open F3, ">out.txt";
while () {
      my $str = $;
      print F3 join ' ' ,map {s/$
/$hashArr{$}/g; $} split / /,$str;
      print F3 "\n";
}

打开F2,“t1.txt”;打开F3,“> out.txt”; while(){my $ str = $; print F3 join'',map {s / $ / $ hashArr {$} / g; $} split / /,$ str;打印F3“\ n”; }

close(F2);
close(F3);