我有一个文件中包含以下数据
typedef INTEGER Id;
typedef Integer32 Id;
typedef Integer32 Id;
typedef Integer32 Id;
typedef INTEGER Identifier;
typedef Integer32 Index;
typedef Unsigned32 Identifier;
typedef Integer32 Index;
typedef Unsigned32 TunnelId;
typedef Unsigned32 TunnelId;
const Unsigned32 maxValue = 65535;
const Integer32 Index_maxValue = 65535;
const Unsigned32 maxValue = 4294967295;
const Unsigned32 Index_maxValue = 65535;
我需要按以下顺序选择变量: 如果变量有......
INTEGER
和Integer32
定义 - 必须选择Integer32
Integer32
和Unsigned32
定义 - 必须选择Unsigned32
INTEGER
和Unsigned32
定义 - 必须选择Unsigned32
预期输出:
typedef Integer32 Id;
typedef Unsigned32 Identifier;
typedef Integer32 Index;
typedef Unsigned32 TunnelId;
const Unsigned32 maxValue = 65535;
const Unsigned32 Index_maxValue = 65535;
我写了下面这段代码...... 但它没有产生上述预期结果。
@file2 = @file // full content of the file in an array
for ($i = 0; $i <= $#file; $i++) {
$temp = $file[$i];
$check = $file[$i];
$check =~ s/^\s+//;
@fields = split(/ /, $check);
@grepNames = grep(/$fields[2]/, @file2);
if($#grepNames >= 1) {
for ($j = 1; $j <= $#file; $j++) {
if( $file[$i] =~ /INTEGER/ && $file[$j] =~ /Unsigned32/ ) {
push(@data, $file[$j]);
}
elsif( $file[$i] =~ /INTEGER/ && $file[$j] =~ /Integer32/ ) {
push(@data, $file[j]);
}
elsif( $file[$i] =~ /Unsigned32/ && $file[$j] =~ /Integer32/ ) {
push(@data, $file[i]);
}
}
}
答案 0 :(得分:3)
尽管你已经接受了 0%的问题(提出这个数字是非常公平的),这里是对你的代码的分析,这样你就可以写得更好(和工作)下次Perl。
始终use strict
和use warnings
,尤其是当您试图弄清楚脚本无法正常工作或您不熟悉Perl的原因时。通常,这些编译指示会提醒您每个人偶尔会犯的大多数愚蠢错误。
Perl并没有强迫你编写好的代码(和TIM TOWDTY),但大多数时候你应该坚持使用Perl的strict
子集,除非你有一个非常好的原因。
使用strict
意味着您必须使用my
声明所有变量,除非您有充分的理由。我认为声明变量是一件好事。
大多数内置函数不需要用于分隔其参数的parens。即<{1}}和split(/ /, $check)
在大多数情况下是相同的。
此外,Perl很少需要split / /, $check
循环结构,尤其是当最后一部分为for(INIT; COMPARE; INCREMENT)
时。相反,您可以使用$i++
- 语法和范围:
foreach
并且:可以避免什么不好的习语
我已经指出所有变量都应该用for my $i ($MIN .. $MAX)
声明,并且有更好的循环语法可用。
my
@file2 = @file // full content of the file in an array
没有引入评论。它是 defined-或运算符。此外,此语句不会被//
终止。这会使Perl感到困惑,因为以下;
循环是同一语句的一部分 - 但这是无效的。
此外,您不会更改for
或@file2
的内容,因此无需复制。
@file
您永远不会使用$temp = $file[$i];
。
$temp
使用此@grepNames = grep(/$fields[2]/, @file2);
来查找包含相同变量名的行数。当您稍后再次遍历grep
中的所有元素时,这是超级流畅的。
@file
你写的是问题: if($#grepNames >= 1)
中的最高索引是否大于或等于1?而你可能意味着我们有多个匹配吗? 。我把它写成
@grepNames
然而,这主要是一种风格评论。
if (@grepNames > 1)
等什么?如果if( $file[$i] =~ /INTEGER/ ...
包含$file[$i]
,则INTEGER
或$check
也会包含$temp
。使用标量而不是数组下标时,可以节省一些输入。
push(@data, $file[$j]);
即使您已经有一个具有相同变量名称的行,也可以将某些内容推送到@data
。更糟糕的是,如果@file
包含 n 元素,那么内部for
循环将迭代 n - 1 元素,并将某些内容推送到{{ 1}}在大多数情况下,使算法 O(n²)
@data
这是一个表(根据您的规则)表明哪个元素应该进入 i \ j | INTEGER | Int32 | UInt32
--------+---------+-------+-------
INTEGER | - | j | j
Int32 | i | - | j
UInt32 | i | i | -
的表格。您可能希望将此表与@data
/ if
进行比较,并确定是否可能缺少某些案例。
elsif
您在push(@data, $file[j]);
之前忘记了$
sigil。
您的算法在 O(n²)中运行,或者更确切地说是 O(n *(2n - 1))。但是,您的问题可以在 O(n)中解决。
我将问题视为:
输入中的每一行都有一个标识符和一个相关的权重。
对于输出,要选择具有相同标识符的所有行的集合中具有最小权重的行。如果两条或更多条线具有相同的最小权重,则可以选择这些最小线中的任何一条。
行的权重取决于行中第二个单词的关键字:
j
如果第二个单词不是这些关键字,则应该抛出错误。
每个标识符的第一次次出现的顺序在输入和输出中都是相同的。
在我的解决方案中(如下所示),我使用第1个和第3个单词作为标识符。如果输出中已存在一行,则在当前行的权重较低时更新它。
Unsigned32 => 1,
Integer32 => 2,
INTEGER => 3,
输出:
#!/usr/bin/perl
use strict; use warnings;
my @data;
my %index;
while (<DATA>) {
$_ =~ s/^\s+//;
my @fields = split /\s+/, $_, 3;
@fields = (@fields[0 .. 1], split /(?=\W)/, $fields[2], 2);
my ($class, $type, $name, $rest) = @fields;
if (defined $index{$class}{$name}) {
# we have a predecessor
my $index = $index{$class}{$name};
$data[$index][1] = (sort compareTypes $data[$index][1], $type)[0];
} else {
push @data, \@fields;
$index{$class}{$name} = $#data;
}
}
foreach (@data) {
my @fields = @$_;
print "@fields[0..2]$fields[3]";
}
sub compareTypes {
my %weight = (
Unsigned32 => 1,
Integer32 => 2,
INTEGER => 3,
);
my $weight_a = $weight{$a} // die "undefined type $a";
my $weight_b = $weight{$b} // die "undefined type $b";
return $weight_a <=> $weight_b;
}
__DATA__
typedef INTEGER Id;
typedef Integer32 Id;
typedef Integer32 Id;
typedef Integer32 Id;
typedef INTEGER Identifier;
typedef Integer32 Index;
typedef Unsigned32 Identifier;
typedef Integer32 Index;
typedef Unsigned32 TunnelId;
typedef Unsigned32 TunnelId;
const Unsigned32 maxValue = 65535;
const Integer32 Index_maxValue = 65535;
const Unsigned32 maxValue = 4294967295;
const Unsigned32 Index_maxValue = 65535;
答案 1 :(得分:0)
解决了这个问题,附上了工作代码。
#!/opt/perl/bin/perl
open (DF, "< UNIQ_DEF.txt");
open (DR, "> DEF_REM.txt");
my @var = <DF>;
my @param =();
my @param2=@var;
for ($i=0; $i<=$#var;$i++)
{
$temp=$var[$i];
$check=$var[$i];
$check=~s/^\s+//;
@params=split(/ /, $check);
if (defined $params[2]){
@Names = grep(/$params[2]/, @param2);
if($#Names >= 1){
if ($Names[0] =~ /Unsigned32/ && $Names[1] =~ /Unsigned32/) {
print DR $Names[0];
} elsif($Names[0] =~ /INTEGER/ && $Names[1] =~ /Unsigned32/) {
print DR $Names[1];
} elsif($Names[0] =~ /Integer32/ && $Names[1] =~ /Integer32/) {
print DR $Names[1];
} elsif($Names[0] =~ /INTEGER/ && $Names[1] =~ /Integer32/) {
print DR $Names[1];
} elsif($Names[0] =~ /Integer32/ && $Names[1] =~ /Unsigned32/) {
print DR $Names[1];
} elsif($Names[0] =~ /Unsigned32/ && $Names[1] =~ /Integer32/) {
print DR $Names[0];
} else {
print DR $var[$i];
}
} else {
print DR $var[$i];
}
} else {
print DR $var[$i];
}
}
close(DF);
close(DR);