搜索字符串的前面以替换字符串Perl的结尾

时间:2017-03-14 16:46:08

标签: string perl replace split

在这里得到一些帮助之后我就想到了(我希望通过尝试将多个脚本放在一起来学习)。下面的脚本将执行HW和OW替换,但不运行if语句。

*#*!/usr/bin/perl  
use strict;  
use warnings 'all';
$^I = '.bak'; # create a backup copy 
while (<>) {
   s/HW/HT/g; # do the replacement of HW with HT
   s/OW/OT/g; # do a second replacement OW with OT
*#* Hopefully run the if statement       
   my @parts = /\s*\S+/g;
   if ( $parts[1] =~ s/([HO])W/$1T/ ) {
    $parts[5] = sprintf '%*d',
            length $parts[5],
            $parts[1] =~ /HT/ ? 2002 : 2001;
      }
print @parts, "\n";
}

如果人们遇到类似的问题,我已将其余部分留在下面。

我想通过在字符串开头搜索特定字母来使用Perl替换文件中的文本。例如,这是文件的一部分:

 6  HT     4.092000    4.750000   -0.502000     0     5     7
 7  HT     5.367000    5.548000   -0.325000     0     5     6
 8  OT    -5.470000    5.461000    1.463000     0     9    10
 9  HT    -5.167000    4.571000    1.284000     0     8    10
10  HT    -4.726000    6.018000    1.235000     0     8     9
11  OT    -4.865000   -5.029000   -3.915000     0    12    13
12  HT    -4.758000   -4.129000   -3.608000     0    11    13

我想使用HT作为搜索,并且可以使用2002替换零列中的“0”。我知道如何替换整列零,但我不知道如何使其特定于行。在使用HT作为搜索后,我需要搜索OT并将0列替换为2001

基本上我需要搜索一个标识该行的字符串,并替换该行的特定字符串,而其间的文本是可变的。输出需要打印到new_file.xyz。我也会在很多文件上反复这样做。 谢谢你的帮助。

这是我正在使用的python代码,但无法弄清楚如何使“file.txt”成为接受命令后键入的文件的变量。此代码要求我每次使用时都将“file.txt”更改为文件的名称。我也无法打印到新文件。

python代码:

#!/usr/bin/python

with open('file.txt') as f:
    lines = f.readlines()
    new_lines = []
    for line in lines:
        if "HT" in line:
            new_line = line.replace(' 0 ', '2002')
            new_lines.append(new_line)
        else:
            new_lines.append(line)
    content = ''.join(new_lines)
    print(content)

我已经能够在Perl中完成一些工作,并希望有一个脚本可以按顺序执行所有替换步骤,因为所有HT都以{{1}开头并且所有HW都以OT开头。 Perl脚本:

OW

感谢您的帮助。
哦,我很遗憾仅限于Python 2.7,因为有人建议使用python 3.0的代码。我纯粹是大学集群的用户,但会询问有关升级python的问题。

3 个答案:

答案 0 :(得分:2)

更新

所以 想要做的就是在第二列中将所有HW更改为HT并将OW更改为OT,并且如果为OW,则将第6列更改为2001,将HW更改为2002?

看起来像这样

use strict;
use warnings 'all';

while ( <DATA> ) {

    my @parts = /\s*\S+/g;

    if ( $parts[1] =~ s/([HO])W/$1T/ ) {

        $parts[5] = sprintf '%*d',
                length $parts[5],
                $1 eq 'H' ? 2002 : 2001;
    }

    print @parts, "\n";
}


__DATA__
 6  HW     4.092000    4.750000   -0.502000     0     5     7
 7  HW     5.367000    5.548000   -0.325000     0     5     6
 8  OW    -5.470000    5.461000    1.463000     0     9    10
 9  HW    -5.167000    4.571000    1.284000     0     8    10
10  HW    -4.726000    6.018000    1.235000     0     8     9
11  OW    -4.865000   -5.029000   -3.915000     0    12    13
12  HW    -4.758000   -4.129000   -3.608000     0    11    13

输出

 6  HT     4.092000    4.750000   -0.502000  2002     5     7
 7  HT     5.367000    5.548000   -0.325000  2002     5     6
 8  OT    -5.470000    5.461000    1.463000  2001     9    10
 9  HT    -5.167000    4.571000    1.284000  2002     8    10
10  HT    -4.726000    6.018000    1.235000  2002     8     9
11  OT    -4.865000   -5.029000   -3.915000  2001    12    13
12  HT    -4.758000   -4.129000   -3.608000  2002    11    13


如果它很重要,这个解决方案会注意保持每行中所有值的位置不变

通过检查第二个字段是否包含字符串HTOT来选择要修改的行。鉴于您提供的小数据样本,我不知道这是否足够

这是出于演示目的。我相信您可以修改代码以在必要时打开外部文件,并从DATA

的其他文件句柄中读取数据
use strict;
use warnings 'all';

while ( <DATA> ) {

    my @parts = /\s*\S+/g;

    if ( $parts[1] =~ /[HO]T/ ) {

        $parts[5] = sprintf '%*d',
                length $parts[5],
                $parts[1] =~ /HT/ ? 2002 : 2001;
    }

    print @parts, "\n";
}


__DATA__
 6  HT     4.092000    4.750000   -0.502000     0     5     7
 7  HT     5.367000    5.548000   -0.325000     0     5     6
 8  OT    -5.470000    5.461000    1.463000     0     9    10
 9  HT    -5.167000    4.571000    1.284000     0     8    10
10  HT    -4.726000    6.018000    1.235000     0     8     9
11  OT    -4.865000   -5.029000   -3.915000     0    12    13
12  HT    -4.758000   -4.129000   -3.608000     0    11    13

输出

 6  HT     4.092000    4.750000   -0.502000  2002     5     7
 7  HT     5.367000    5.548000   -0.325000  2002     5     6
 8  OT    -5.470000    5.461000    1.463000  2001     9    10
 9  HT    -5.167000    4.571000    1.284000  2002     8    10
10  HT    -4.726000    6.018000    1.235000  2002     8     9
11  OT    -4.865000   -5.029000   -3.915000  2001    12    13
12  HT    -4.758000   -4.129000   -3.608000  2002    11    13

答案 1 :(得分:1)

看起来它使用固定宽度字段,所以

sub trim { $_[0] =~ s/^\s+//r =~ s/\s+\z//r }

while (<>) {
   my $code = trim(substr($_, 2, 4));
   if ($code eq "HW") {
      substr($_,  2, 4, "  HT");
      substr($_, 43, 6, "  2002");
   }
   elsif ($code eq "OW") {
      substr($_,  2, 4, "  OT");
      substr($_, 43, 6, "  2001");
   }

   print;
}

清洁剂:

sub parse {
   my ( @format, @row );
   while ($_[0] =~ /\G\s*(\S+)/g) {
      push @row, $1;
      push @format, '%'.( $+[0] - $-[0] ).'s';
   }
   return ( join('', @format)."\n", @row );
}

while (<>) {
   my ($format, @row) = parse($_);

   if    ($row[1] eq "HW") { $row[1] = "HT";  $row[5] = 2002; }
   elsif ($row[1] eq "OW") { $row[1] = "OT";  $row[5] = 2001; }

   printf($format, @row);
}

答案 2 :(得分:0)

似乎您想使用正则表达式来执行字符串替换。 IMO,你应该在一次替换中完成所有操作,因为它不是更复杂,它可能更快,更不容易出错(因为更短)。

以下是我了解您的要求: 在你的行中,你有一个H或一个O,后跟一个你要强制为T的T或W,然后是你要复制的3个字段,然后是第4个字段。如果第4个字段为0,则需要根据字母H或O将其替换为2002或2001。

这给出了:

while (my $line = <>) {
    $line =~ s/(\s*)([HO])(T|W)(\s+\S+\s+\S+\s+\S+)(\s+\d+)/$1.$2.'T'.$4.($5 == 0 ? ($2 eq 'H' ? '  2002' : '  2001') : $5)/eg;
    print $line;
}