【问题标题】:How can I parse the output of lshw using Perl regexes?如何使用 Perl 正则表达式解析 lshw 的输出?
【发布时间】:2018-04-13 11:34:00
【问题描述】:

我正在尝试使用此代码将 lshw 输出解析为哈希,目前为止有效。

  use strict;
  use warnings;

  my (%lshw,$key,$value);
  while (<>){
  s/#.*//;                # no comments
  s/^\s+//;               # no leading whites
  s/\s+$//;               # no trailing whites
  next unless length;     # anything left?
  if (/(?<key>.*?):\s+(?<value>.*)/x){
    $lshw{$+{key}} = $+{value};
  }
}

# remove white spaces in hash keys
for $key (keys %lshw){
  $value = delete $lshw{$key};
  for ($key){
    s/\s+//g;
   }
  $lshw{$key} = $value;
  }

my $logname   = $lshw{'logicalname'};
print "Logical name\t $logname\n";

但是当我遇到以下配置时我会感到挣扎:

clock: 33Mhz 
width: 32 bits 
capacity: 1Gbit/s 
configuration:autonegotiation=on broadcast=yes driver=igb driverversion=5.3.0-k duplex=full firmware=1.63, 0x800009fa ip=[REMOVED] latency=0 link=yes multicast=yes port=twisted pair speed=1Gbit/s`

我正在尝试一种 hoh 方法,但没有找到如何拆分键/值的解决方案,因为它包含多个单词值,例如 port=twisted pair。 关键始终是一个单词。

谁能告诉我如何解决这个问题?

(感谢 simbabque 的严格/警告提示)

【问题讨论】:

  • =左边的config键总是一个字吗?
  • 另外,您想使用use strictuse warnings 并使用它们编译您的脚本,然后更新代码。你可以edit你的问题。
  • 到目前为止,您的代码只获得了 key: value.... 的东西,但它不处理该值内的各个对。您是否忘记将该代码添加到问题中?

标签: regex perl


【解决方案1】:

您需要捕获等号后不跟随模式somekeyname= 的所有字符。

#!/usr/bin/env perl

use strict;
use warnings;

my $s = q{configuration: autonegotiation=on broadcast=yes driver=igb driverversion=5.3.0-k duplex=full firmware=1.63, 0x800009fa ip=[REMOVED] latency=0 link=yes multicast=yes port=twisted pair speed=1Gbit/s};

my ($key, $rest) = split /:\s*/, $s, 2;

my %params = ($rest =~ / (\w+) = ((?:. (?! \w+ = ))+) /gx);

use YAML::XS;
print Dump \%params;

输出:

---
autonegotiation: on
broadcast: yes
driver: igb
driverversion: 5.3.0-k
duplex: full
firmware: 1.63, 0x800009fa
ip: '[REMOVED]'
latency: '0'
link: yes
multicast: yes
port: twisted pair
speed: 1Gbit/s

此外,您的初始循环可以改进:

 while (<>) {
     next if /^#/; # skip comments
     /\S/ or next; # skip blank lines
     s/^\s+//;
     s/\s+\z//;
     # ...
}

【讨论】:

    【解决方案2】:

    你只需要split配置字符串就可以了

    use strict;
    use warnings 'all';
    use feature 'say';
    
    my $s = 'configuration: autonegotiation=on broadcast=yes driver=igb driverversion=5.3.0-k duplex=full firmware=1.63, 0x800009fa ip=[REMOVED] latency=0 link=yes multicast=yes port=twisted pair speed=1Gbit/s';
    
    say for split /\s+(?=[^\s=]+=)/, $s;
    

    输出

    configuration:
    autonegotiation=on
    broadcast=yes
    driver=igb
    driverversion=5.3.0-k
    duplex=full
    firmware=1.63, 0x800009fa
    ip=[REMOVED]
    latency=0
    link=yes
    multicast=yes
    port=twisted pair
    speed=1Gbit/s
    

    您现在有一个键及其值的列表,按键名正确划分。这应该很容易处理

    【讨论】:

    • 酷,掌握正则表达式在我的下一个愿望清单上;-)
    【解决方案3】:

    鲍罗丁的做法就是这样。

    以防万一您想使用正则表达式对其进行解析,这将起作用并将键与其值分开。

    #!/usr/bin/env perl
    
    use warnings FATAL => 'all';
    use strict;
    my $s = 'configuration: autonegotiation=on broadcast=yes driver=igb driverversion=5.3.0-k duplex=full firmware=1.63, 0x800009fa ip=[REMOVED] latency=0 link=yes multicast=yes port=twisted pair speed=1Gbit/s';
    
    while ($s =~ m/(?<key>[A-Za-z0-9]+)=(?<value>([\/\[\]A-Za-z0-9., -]+)(?= [a-z]+)|([\/\[\]A-Za-z0-9., -]+))/g) {
        print "$+{key} >>  $+{value}\n";
        $s =~ s/$+{key}//;
    }
    

    输出

    autonegotiation >>  on
    broadcast >>  yes
    driver >>  igb
    driverversion >>  5.3.0-k
    duplex >>  full
    firmware >>  1.63, 0x800009fa
    ip >>  [REMOVED]
    latency >>  0
    link >>  yes
    multicast >>  yes
    port >>  twisted pair
    speed >>  1Gbit/s
    

    优点

    • 键/值分离

    缺点

    • 正则表达式中昂贵的正向前瞻

    重构提案

    • 去掉正则表达式中的复杂字符组[\/\[\]A-Za-z0-9., -]
    • 摆脱循环中找到的模式的替换

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多