2

亲爱的世界上我的perl大师们~!

我需要你的帮助。

我有一个字符串文件A和一个数字文件B,如下所示:

档案一:

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE

...依此类推,直到 200。

文件 B:

3, 6, 2, 5, 6, 1, ... 2 

(数组中共有 200 个数字)

然后,使用文件 B 中的数字,我想将每个字符串从起始位置剪切到文件 B 中的字符数。

例如,文件 B 以 3, 6, 2 ... 开头

文件 A 将是

AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
BBBBBBBBBBBBBBBBBBBBBBBBBB
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

像这样。

所以。到目前为止,这是我的代码...

use strict;

if (@ARGV != 2) {
    print "Invalid usage\n";
    print "Usahe: perl program.pl [num_list] [string_file]\n";
    exit(0);
}

my $numbers=$ARGV[0];
my $strings=$ARGV[1];
my $i;

open(LIST,$number);
open(DATA,$strings);

my @list = <LIST>;
my $list_size = scalar @sp_list;


for ($i=0;$i<=$list_size;$i++) {
    print $i,"\n";
    #while (my $line = <DATA>) {    
    }   


close(LIST);
close(DATA);

由于字符串和数字是 200,我将数组更改为标量值,以处理每个字符串的每个数字。

我正在做这件事。我知道我想使用 pos 函数,但我不知道如何将每个数字与每个字符串匹配。是先读字符串吗?或使用 for 知道我必须运行多少次才能达到结果?

您的帮助将不胜感激!

谢谢你。

我也会努力的。需要您的反馈。

4

5 回答 5

5

你用的好,你strict也应该用warnings。其他需要注意的事项:

您应该检查 的返回值open以确保它们没有失败。您还应该使用 的三参数形式open并使用词法文件句柄。特别是在处理命令行参数时,这确实会带来安全风险。

open my $listfh, "<", $file or die $!;

您可能希望使用安全预防措施

use ARGV::readonly;

map您可以使用语句轻松制作数字列表。假设数字在逗号分隔的列表中:

my @list = map split(/\s*,\s*/), <$listfh>;

这将以逗号分隔输入行并去除多余的空格。

读取输入文件时,不需要使用计数器变量。你可以简单地做

open my $inputfh, "<", $file or die $!;
while (<$inputfh>) {
    my $length = shift @list;   # these are your numbers
    chomp;                      # remove newline 
    my $string = substr($_, 0, -$length);  # negative length on substr
    print "$string\n";
}

substr 上的负长度使其在字符串末尾留下那么多字符。

这是一个演示这些原则的单行代码:

perl -lwe '$f = pop;                            # save file name for later
           @nums = map split(/\s*,\s*/), <>;    # process first file
           push @ARGV, $f;                      # put back file name
           while (<>) { 
                my $len = shift @nums; 
                chomp; 
                print substr($_,0,-$len); 
           }' fileb.txt filea.txt

输出:

AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
BBBBBBBBBBBBBBBBBBBBBBBBBB
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
DDDDDDDDDDDDDDDDDDDDDDDDDDD
EEEEEEEEEEEEEEEEEEEEEEEEEE

请注意通过操作来使用隐式打开文件名参数@ARGV-l还使用开关处理换行符。

于 2013-02-15T10:28:51.223 回答
3

这是我的建议。这样做use autodie是为了无需显式检查open调用的状态,并暂时取消定义$/- 输入记录分隔符 - 以便一次性读取所有num_list文件。你不清楚这个文件是否总是只包含一行,在这种情况下你可以省略local $/.

使用正则表达式从文本中提取/\d+/g数字,将输入中的所有数字字符串作为列表返回。

to的第二个参数substr是你想要的子字符串的起始位置,并且使用负数从字符串的末尾而不是开头开始计数。第三个参数是子串中的字符数,第四个是替换目标变量中那个子串的字符串。所以用一个空字符串substr $data, -$n, $n, ''替换长度从末尾$n开始的字符的子字符串 - 即它删除它。$n

请注意,如果您打算从字符串的开头删除给定数量的字符,那么您将 substr $data, 0, $n, ''改为编写。

use strict;
use warnings;
use autodie;

unless (@ARGV == 2) {
  print "Usage: perl program.pl [num_list] [string_file]\n";
  exit;
}

my @numbers;
{
  open my $listfh, '<', $ARGV[0];
  local $/;
  my $numbers = <$listfh>;
  @numbers = $numbers =~ /\d+/g;
};


open my $datafh, '<', $ARGV[1];

for my $i (0 .. $#numbers) {
  print "$i\n";
  my $n = $numbers[$i];
  my $data = <$datafh>;
  chomp $data;
  substr $data, -$n, $n, '';
  print "$data\n";
}   
于 2013-02-15T10:43:52.120 回答
2

这是我将如何做到的。substr是删除部分字符串的函数。从您的示例中,尚不清楚您是要删除开头还是结尾的字符。两种选择都显示在这里:

#!/usr/bin/perl
use warnings;
use strict;

if (@ARGV != 2) {
    die "Invalid usage\n"
        . "Usage: perl program.pl [num_list] [string_file]\n";
}

my ($number_f, $string_f) = @ARGV;

open my $LIST, '<', $number_f or die "Cannot open $number_f: $!";
my @numbers = split /, */, <$LIST>;
close $LIST;

open my $DATA, '<', $string_f or die "Cannot open $string_f: $!";
while (my $string = <$DATA>) {
    substr $string, 0, shift @numbers, q(); # Replace the first n characters with an empty string.

    # To remove the trailing portion, replace the previous line with the following:
    # my $n = shift @numbers;
    # substr $string, -$n-1, $n, q();

    print $string;
}

您没有检查open. 试着记住永远这样做。

在使用它们之前不要声明变量($i这里)。

for如果没有必要,不要使用 C 风格的循环。他们很容易出现围栏错误。

于 2013-02-15T10:26:23.607 回答
0

您可以使用substr()

use strict;
use warnings;

if (@ARGV != 2) {
    print "Invalid usage\n";
    print "Usage: perl program.pl [num_list] [string_file]\n";
    exit(0);
}

my $numbers=$ARGV[0];
my $strings=$ARGV[1];

open my $list, '<', $numbers or die "Can't open $numbers: $!";
open my $data, '<', $strings or die "Can't open $strings: $!";

chomp(my $numlist = <$list>);
my @numbers = split /\s*,\s*/,$numlist;
for my $chop_length (@numbers)
{
   my $data = <$data> // die "not enough data in $strings";
   print substr($data,0,length($data)-$chop_length)."\n";
}
于 2013-02-15T10:17:43.163 回答
0

您的规范说您希望“...将每个字符串从起始位置剪切到文件 B 中的字符数。” 我同意choroba的观点,即是否要剪切字符串开头或结尾的字符并不完全清楚。但是,我倾向于认为,当您说"... from the start position ..."时,您想从开头删除字符,但是类似的字符串ABCDEFGHIJKLMNOPQRSTUVWXYZ012345有助于澄清这个问题。

此选项不像其他解决方案那样具有自我记录性,但随后将对其进行讨论:

use strict;
use warnings;

@ARGV == 2 or die "Usage: perl program.pl [num_list] [string_file]\n";

open my $fh, '<', pop or die "Cannot open string file: $!";
chomp( my @str = <$fh> );

local $/ = ', ';

while (<>) {
    chomp;
    print +( substr $str[ $. - 1 ], $_ ) . "\n";
}

字符串:

ABCDEFGHIJKLMNOPQRSTUVWXYZ012345
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE

数字:

3, 6, 2, 5, 6

输出:

DEFGHIJKLMNOPQRSTUVWXYZ012345
BBBBBBBBBBBBBBBBBBBBBBBBBB
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
DDDDDDDDDDDDDDDDDDDDDDDDDDD
EEEEEEEEEEEEEEEEEEEEEEEEEE

字符串的文件名被pop删除@ARGV(因为pop未使用显式参数 for)并传递open给以将字符串读入@str. 记录分隔符设置为', 'chomp留下数字。当前行号 in$.用作相应元素的索引的一部分,并打印@str字符串中的剩余字符。n

于 2013-02-16T00:44:49.413 回答