所以我遇到了问题,我无法解决。如果我从Perl中的文件中读取一些单词,在该文件中单词不是按顺序排列,而是有一个数字(作为第一个字符)应该是元素构成句子的位置。 0表示位置正确,1表示该单词应位于[1]
等位置。
该文件如下所示: 0This 3a 4sentence 2be 1should
,解决方案应该类似于 0这1应该是3a 4sentence 。
在for
循环中,我浏览了从文件中获取的单词数组,这就是我获取第一个字符(数字)$firstCharacter = substr $words[$i], 0, 1;
的方式,但我不知道知道如何正确更改数组。
这是我使用的代码
#!/usr/bin/perl -w
$arg = $ARGV[0];
open FILE, "< $arg" or die "Can't open file: $!\n";
$/ = ".\n";
while($row = <FILE>)
{
chomp $row;
@words = split(' ',$row);
}
for($i = 0; $i < scalar @words; $i++)
{
$firstCharacter = substr $words[$i], 0, 1;
if($firstCharacter != 0)
{
}
}
答案 0 :(得分:7)
只需使用sort即可。您可以使用列表上下文中的匹配来提取数字,使用\d+
即使数字&gt;也可以使用9:
#! /usr/bin/perl
use warnings;
use strict;
use feature qw{ say };
my @words = qw( 0This 3a 4sentence 2be 1should );
say join ' ', sort { ($a =~ /\d+/g)[0] <=> ($b =~ /\d+/g)[0] } @words;
如果您不介意警告,或者您愿意将其关闭,您可以直接对单词进行数字比较,Perl将自行提取数字前缀:
no warnings 'numeric';
say join ' ', sort { $a <=> $b } @words;
答案 1 :(得分:3)
假设您有一个这样的数组:
my @words = ('0This', '3a', '4sentence', '2be', '1should');
你希望它像这样排序:
('0This', '1should', '2be', '3a', '4sentence');
这有两个步骤。首先是提取前导号码。然后按那个数字排序。
您无法使用substr
,因为您不知道该数字可能有多长。例如,('9Second', '12345First')
。如果您只查看第一个字符,则会得到9和1,并对它们进行错误排序。
相反,您可以使用正则表达式来捕获数字。
my($num) = $word =~ /^(\d+)/;
有关其工作原理的详情,请参阅perlretut,尤其是documentation。
既然您可以捕获这些数字,那么他们可以Extracting Matches。 sort
不是自己循环,而是为您处理排序。您所要做的就是提供排序标准。在这种情况下,我们从每个单词中捕获数字(按排序分配给$ a和$ b)并将它们作为数字进行比较。
@words = sort {
# Capture the number from each word.
my($anum) = $a =~ /^(\d+)/;
my($bnum) = $b =~ /^(\d+)/;
# Compare the numbers.
$anum <=> $bnum
} @words;
有多种方法可以提高效率,尤其是sort。
你也可以作弊。
如果你要求Perl将某些东西视为一个数字,那么它将最大程度地遵守。如果字符串以数字开头,它将使用它并忽略其余部分,但它会抱怨。
$ perl -wle 'print "23foo" + "42bar"'
Argument "42bar" isn't numeric in addition (+) at -e line 1.
Argument "23foo" isn't numeric in addition (+) at -e line 1.
65
我们可以通过直接将单词作为数字进行比较来利用它来简化排序。
{
no warnings 'numeric';
@words = sort { $a <=> $b } @words;
}
请注意,我关闭了将单词用作数字的警告。 use warnings
和no warnings
仅在当前区块中生效,因此将no warnings 'numeric'
和sort
放在自己的区块中我只关闭了该区域的警告排序声明。
最后,如果单词在文件中,您可以从命令行使用Unix sort
实用程序。使用-n
进行“数字排序”,它将执行与上述相同的操作。
$ cat test.data
00This
3a
123sentence
2be
1should
$ sort -n test.data
00This
1should
2be
3a
123sentence
答案 2 :(得分:1)
您应该可以拆分空格,这将使数字成为单词的第一个字符。有了这个假设,你可以简单地使用数字比较运算符(<=>
)进行比较而不是字符串比较(cmp
)。
运算符非常重要,因为如果比较字符串,则会使用第一个字符,这意味着10
,11
和12
会出现故障,并列在{{{}附近1}}(1
代替1,10,11,12,2,3,4…
)。
注意: @schwern评论了一个重点。如果你使用警告 - 你应该 - 你会收到警告。这是因为内部比较变量1,2,3,4…10,11,12
和$a
的值不是数字,而是字符串(例如,`&#34; 0这个&#34;,&#34; 3a& #34)。我已更新以下键盘并提供了更合适的替代方法以避免此问题。
$b
一种方法是使用use strict;
use warnings;
my $line = q{0This 3a 4sentence 2be 1should};
my @words = split /\s/,$line;
my @sorted = sort {$a <=> $b} @words;
print qq{
Line: $line
Words: @words
Sorted: @sorted
};
中的no warnings 'numeric'
来忽略警告。如他所示,关闭一个区块中的警告将在之后重新启用它,与Schwern's answer相比可能有点万无一失,后者将其应用于更广泛的范围。
Choroba's answer通过在内部解析这些值中的数字来工作。代码行数要少得多,但出于性能原因,我通常会反对这一点。正则表达式不是每个单词只运行一次,而是在排序过程中多次运行。
另一种方法是删除数字并将其用于排序比较。我尝试通过创建哈希来执行此操作,其中键将是数字,值将是单词。
一旦你有一个数组,其值是以数字为前缀的单词,你可以很容易地将这些数字/单词组合分成一个散列,其中键作为数字和值作为单词。这是通过使用split
完成的。
关于split
语句的重要注意事项是传递 limit (在本例中为2
),这限制了字符串的最大字段数分成。
然后在map
中使用这两个值来构建键/值赋值。因此,"0This"
分为"0"
和"This"
,以便在哈希中使用"0"=>"This"
use strict;
use warnings;
my $line = q{0This 3a 4sentence 2be 1should};
my @words = split /\s/, $line; # [ '0This', '3a', ... ]
my %mapped = map { split /(?=\D)/, $_, 2 } @words; # { '0'=>'This, '3'=>'a', ... }
my @sorted = @mapped{ sort { $a <=> $b } keys %mapped }; # [ 'This', 'should', 'be', ... ]
print qq{
Line: $line
Words: @words
Sorted: @sorted
};
这也可以进一步优化,但使用多个变量来说明过程中的步骤。