1

我有一个文件,其中包含以下数据

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;

我需要按以下顺序选择变量:如果变量有……</p>

  • INTEGERInteger32 定义 -Integer32 必须选择
  • Integer32Unsigned32定义 -Unsigned32必须选择
  • INTEGERUnsigned32定义 -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]);
         }
    }
}
4

2 回答 2

3

尽管您接受了0%的问题(提高这个数字是非常公平的),但这里是对您的代码的分析,以便您下次可以编写更好(和工作)的 Perl。

关于编写 Perl 的一般评论

纪律与混乱

总是use strictuse warnings,尤其是当您试图找出脚本不工作的原因或当您是 Perl 新手时。通常,这些 pragma 会提醒您每个人偶尔会犯的最愚蠢的错误。

Perl 不会强迫您编写好的代码(和 TIM TOWDTY),但大多数时候您应该坚持使用strictPerl 的子集,除非您有充分理由。

使用strict 意味着您必须使用 声明所有变量my,除非您有充分的理由。我认为声明变量是一件好事。

Perl 不是 C

大多数内置函数不需要括号来分隔它们的参数。即split(/ /, $check)split / /, $check在大多数情况下都是一样的。

此外,Perl 很少需要for(INIT; COMPARE; INCREMENT)循环结构,尤其是当最后一部分是$i++. 相反,您可以使用foreach-syntax 和range

for my $i ($MIN .. $MAX)

为什么你的代码不起作用

还有:有什么不好的成语可以避免

我已经指出,所有变量都应该声明为,my并且有更好的循环语法可用。

@file2 = @file // full content of the file in an array

//不引入评论。它是定义或运算符。此外,此语句不会以;. 这会使 Perl 感到困惑,因为下面的for循环是同一语句的一部分——但这是无效的。

此外,您不会更改@file2or的内容@file,因此不需要进行复制。

$temp = $file[$i];

你从不使用$temp.

@grepNames = grep(/$fields[2]/, @file2);

您可以使用它grep来找出有多少行包含相同的变量名称。当您稍后再次遍历所有元素时,这是多余的。@file

if($#grepNames >= 1)

你写的是问题:最高索引是否@grepNames大于或等于1?而你可能是说我们有不止一场比赛吗?. 我把它写成

if (@grepNames > 1)

然而,这主要是一种风格上的评论。

if( $file[$i] =~ /INTEGER/ ...

等什么?如果$file[$i]包含INTEGER,那么将$check$temp。使用标量而不是数组下标时,您可以节省一些输入。

push(@data, $file[$j]);

@data即使您已经有一条具有相同变量名的行,您也可以将某些东西推到上面。更糟糕的是,如果@file包含n 个元素,那么内部for循环会迭代n - 1 个@data元素,并且在大多数情况下你会推送一些东西,使你的算法O(n²)

  i \ j | INTEGER | Int32 | UInt32
--------+---------+-------+-------
INTEGER | -       | j     | j
Int32   | i       | -     | j
UInt32  | i       | i     | -

这是一个表格,说明(根据您的规则)应该将哪个元素放入@data. 您可能想将此表与您的if/ elsifs 进行比较,并确定是否可能缺少某些情况。

push(@data, $file[j]);

你之前忘记了$印记j

更好的解决方案

您的算法在O(n²)中运行,或者更确切地说是O(n * (2n - 1))。但是,您的问题可以在O(n)中解决。

我将问题视为:

输入中的每一行都有一个标识符和一个相关的权重。

对于输出,从具有相同标识符的所有行的集合中选择具有最小权重的行。如果两条或多条线具有相同的最小权重,则可以选择这些最小线中的任何一条。

一行的权重取决于该行中的第二个单词是什么关键字:

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;

输出:

typedef Integer32 Id;
typedef Unsigned32 Identifier;
typedef Integer32 Index;
typedef Unsigned32 TunnelId;
const Unsigned32 maxValue = 65535;
const Unsigned32 Index_maxValue = 65535;  
于 2012-09-29T09:00:49.293 回答
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);
于 2012-09-29T11:16:54.960 回答