按字母顺序排列第一个数组位置的整个单词

时间:2017-07-20 09:44:34

标签: perl

我有一个文件,其值由管道|

分隔

输入

car tree alfa young|salt brick|23223|
emilia jack albert| way to go|56566|

我正在尝试按字母顺序对第一列进行排序,并将已排序的文件写出来。

结果:

alfa car tree young|salt brick|23223|
albert emilia jack| way to go|56566|

我尝试过: 可以排序第一个数组位置,但不能写出所有文件内容。

 $filename = 'test.dat';
 open (INPUT,"$filename");
 open (OUTPUT,">out.dat");

 while (<INPUT>)
 {
   @array = split('\|');
   @arr = split(' ',$array[0]);
   $,=" ";
   print OUTPUT sort @arr,"\n";
  }
   close (INPUT);
   close (OUTPUT);

对每行中的所有内容进行排序。

 $filename = 'test.dat';
 open (INPUT,"$filename");
 open (OUTPUT,">out.dat");

 while (<INPUT>)
 {
   @arr = split(' ');
   $,=" ";
   print OUTPUT sort @arr,"\n";
  }
   close (INPUT);
   close (OUTPUT);

4 个答案:

答案 0 :(得分:2)

如果您偏离代码中硬编码文件名的想法,您的程序将更加灵活。从STDIN读取并尽可能写入STDOUT是一个更好的主意。这就是这段代码的作用。

#!/usr/bin/perl

use strict;
use warnings;

while (<>) {
  # Split the record into the first field (the one we want to sort)
  # and everything else.
  my ($first, $rest) = split /\|/, $_, 2;

  # Split the first record into words
  my @words = split /\s+/, $first;

  # Sort @words and then join the line back together and print it.
  print join(' ', sort @words), "|$rest";
}

如果我们将此程序存储在名为reorder的文件中,我们可以从命令行提示符运行它,如下所示:

$ ./reorder < test.dat > out.dat

我们避免打开任何文件句柄(操作系统为我们做了),如果文件名发生变化,我们就不需要更改程序。

答案 1 :(得分:2)

perl -pe 's/^([^|]+)/@a = sort split ' ', $1; "@a";/e' myfile

答案 2 :(得分:1)

split行放入数组后

my @ary = split '\|';

您需要split第一个元素,sort列表,join它回来

my $first = join ' ', sort split ' ', shift @ary;

其中shift删除(并返回)第一个元素。

然后构建字符串

my $new_string = join '|', $first, @ary;

这可以在没有临时变量的情况下完成。最后两个步骤可以在一个语句中完成,所有这些都在print语句中完成。

评论

  • 请始终使用use warnings;use strict;

  • 开始您的计划
  • 使用open

    的三参数形式
    open my $fh, '<', $file or die "Can't open $file: $!";
    

    所以使用词法文件句柄$fh),而不是bareword(typeglobs,FH)。

  • 不引用不需要引用的内容 - 甚至可能导致错误!例如,请参阅What's wrong with always quoting (perlfaq4)。感谢Sinan Ünür发表评论。

您也可以使用正则表达式

$line =~ s/(.*?)\|/join(" ", sort split " ", $1).q(|)/e;

这会捕获第一个字段(直到管道),并在其上运行上面的代码,由/e修饰符提供,这使得替换部分被评估为代码。

我们还需要匹配管道,然后将其放回去。使用lookahead

可以避免这种情况
$line =~ s/(.*?)(?=\|)/join(' ', sort split ' ', $1)/e;

仅断言(?=...)内的模式存在,而不消耗它。

答案 3 :(得分:0)

你的第一段代码非常接近正确。您只输出第一列 - 您需要打印出@array的内容。如果用排序结果替换@array的第一个元素,那么你就可以这样写出来。

@array = split('\|');
$array[0] = join(" ",sort split(' ',$array[0]));
print OUTPUT join("|",@array),"\n";