【问题标题】:Search the front of a string to replace the end of the string Perl搜索字符串的前面以替换字符串的结尾 Perl
【发布时间】:2017-08-05 03:14:03
【问题描述】:

在这里得到一些帮助后,我想到了(我希望通过尝试将多个脚本放在一起来学习)。下面的脚本将执行 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 都以 HW 开头,所有OTOW 开头。 Perl 脚本:

#!/usr/bin/perl

use strict;
use warnings;

$^I = '.bak'; # create a backup copy 

while (<>) {
   s/HW/HT/g; # do the replacement
   s/OW/OT/g; # do a second replacement
   print; # print to the modified file
}

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

【问题讨论】:

  • 你试过什么?你在 Python 中想出了什么不起作用的东西?请向我们展示您的代码并解释哪些部分不起作用。
  • 我也希望使用 PERL,因为我已经想出了如何用 HT 替换 HW,用 OT 替换 OW,我希望能够将所有内容组合到一个 PERL 脚本中运行任何输入文件。
  • 如果你已经有了,请出示。你可以edit你的问题。现在的情况,社区将关闭它,因为看起来你希望我们为你做你的工作。我们不喜欢这里。
  • PYTHON 的主要问题是我不知道如何接受人们的建议并让他们打印到一个新文件中,我不知道如何制作“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 中可以做的事情,我承认这很容易,但花了我很多时间。 #!/usr/bin/perl 使用严格;使用警告; $^I = '.bak'; # 创建一个备份副本 while () { s/HW/HT/g; # 替换 s/OW/OT/g; # 进行第二次替换打印; # 打印到修改后的文件 }

标签: string perl replace split


【解决方案1】:

更新

所以你真正想要做的是将第二列中的所有HW 更改为HTOWOT,如果为@,则将第六列更改为2001 987654325@ 和 2002 为 HW

看起来像这样

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



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

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

这是出于演示目的。我相信您能够在必要时修改代码以打开外部文件,并从 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

【讨论】:

  • 对不起,我是新手。我花了很多年研究小分子,只是在 vi 中使用了 x 和 dd!我们现在正在进入数百个分子系统。感谢您的帮助。
【解决方案2】:

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

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);
}

【讨论】:

  • 您好 ikegami,首先:感谢您格式化我的问题,我正在努力学习如何更好地使用它!感谢您提供的脚本,我将尝试理解它,但如果我感到困惑,可能会问您一些后续问题。
  • 我将测试两者,看看我是否能弄清楚如何在 HW 替换为 HT 的部分中添加,然后找到 HT 并将 0 替换为 2002 等。
  • @Drewucla:你应该在一开始就提出整个问题。这最好一次完成,而不是两个阶段。看我的回答。
  • 您好,上面的脚本运行良好,但我尝试修改它以在运行 Borodin if 语句之前将所有 HW 替换为 HT,并将所有 OW 替换为 OT。代码只做了 HW 和 OW 替换,而不是 if 语句,为什么?我会将代码放在问题中(希望格式正确)
  • 您执行s/HW/HT/g,然后检查第二个s/HW/HT/g 是否成功。当然不会。摆脱第一个s/HW/HT/g。 /// 添加了更清洁的解决方案
【解决方案3】:

您似乎想使用正则表达式来执行字符串替换。 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;
}

【讨论】:

    猜你喜欢
    • 2015-10-03
    • 1970-01-01
    • 2012-07-04
    • 1970-01-01
    • 2017-04-16
    • 2020-01-06
    • 2018-10-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多