【问题标题】:extracting hex values from line in perl从perl中的行中提取十六进制值
【发布时间】:2016-09-23 04:50:24
【问题描述】:

我有一个这样的字符串,我只需要从行中提取十六进制值,然后将十六进制值复制到新文件中。

文件中的输入行:

ame (header(...))  0x0D 0x0C 0x4A 0x00 0x01 0x00, 0x02 0x00, 0x0A 0x00,  
0x04 0x00, 0x04 0x05 0x00 0x001f 0x001f 0x007f 0x00, 0x002b 0x007f 0x0000
0x00 0x0000 0xffffffaf 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00, 
(non_t_crmax 0x0D 0x00,  TDD 0x5D 0x2760 Invalid 0x0000 0x02 0x00, 
(rat_type (rat_type (rat_type (rat_type (rat_type (rat_type (rat_type

预期输出:

0x0D, 0x0C, 0x4A, 0x00, 0x01, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x04, 0x00, 
0x04, 0x05,0x00, 0x001f, 0x001f, 0x007f, 0x00, 0x002b, 0x007f, 0x0000, 0x00 
0x0000, 0xffffffaf,0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0D, 
0x00,0x5D 0x2760 0x0000 0x02 ,0x00,  

【问题讨论】:

  • my @hex = $line =~ /(0x[0-9A-F]+)/ig;
  • 在您的预期输出中,逗号和空格不一致。这是一个错误吗?

标签: perl


【解决方案1】:
#!/usr/bin/perl
use strict;
use warnings;

my $input = << 'DATA'; # this is what you read from your file
ame (header(...))  0x0D 0x0C 0x4A 0x00 0x01 0x00, 0x02 0x00, 0x0A 0x00,  
0x04 0x00, 0x04 0x05 0x00 0x001f 0x001f 0x007f 0x00, 0x002b 0x007f 0x0000
0x00 0x0000 0xffffffaf 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00, 
(non_t_crmax 0x0D 0x00,  TDD 0x5D 0x2760 Invalid 0x0000 0x02 0x00, 
(rat_type (rat_type (rat_type (rat_type (rat_type (rat_type (rat_type
DATA

my @hexvals = $input =~ /(0x[\da-f]+)/ig;

print join ', ', @hexvals; # output

输出:

0x0D, 0x0C, 0x4A, 0x00, 0x01, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x04, 0x00,
0x04, 0x05, 0x00, 0x001f, 0x001f, 0x007f, 0x00, 0x002b, 0x007f, 0x0000,
0x00, 0x0000, 0xffffffaf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0x0D, 0x00, 0x5D, 0x2760, 0x0000, 0x02, 0x00

【讨论】:

  • 如果值大于 1 字节(0x002b 和 0xffffffaf ),那么我需要用 0x00,0x2b 和 0xff,0xff,0xff,0xaf 分割怎么做
  • @Abhishek:这是一个不同的问题。请把它放在一个新的帖子中。
【解决方案2】:

这里有一个简单的 perl 脚本(带有 cmets),解析输入和输出你需要什么。

#!/usr/bin/env perl

# buffer creation, will contain all desired values
my @buf;

# main loop from stdin
while (<>) {


      # 2. push value in @buf if match desired regrex
  map({ push(@buf,$_) if $_ =~ /^0x[0-9a-f]+$/i}
      # 1. split every line on null char
      split(/\s+/, $_));
} 

# print comma separated result
print join(",", @buf)."\n";

例子:

chmod +x script.pl
cat data | ./script.pl
mycoolcommand | ./script.pl

输出:

0x0D,0x0C,0x4A,0x00,0x01,0x02,0x0A,0x04,0x04,0x05,0x00,0x001f,0x001f,0x007f,0x002b,0x007f,0x0000,0x00,0x0000,0xffffffaf,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0D,0x5D,0x2760,0x0000,0x02

【讨论】:

  • 最好你应该使用grep而不是map
  • map 似乎比grep 更具延展性和可扩展性,但能给我举个例子吗? :)
  • 我相信mapgrep 都是可延展的可扩展的,这取决于它们的使用地点。这里例如:map({ push(@buf,$_) if $_ =~ /^0x[0-9a-f]+$/i} split(/\s+/, $_));可以替换为my @buf = grep { /^0x[0-9a-f]+$/i } split(/\s+/, $_)
  • @MathieuK: map 在 void 上下文中使用始终是代码异味,通常应替换为 foreach 循环。要按预期使用map(即转换列表),您的代码应重写为@buf = map { /^0x[0-9a-f]+$/i ? $_ : () } split。但正如@AruneshSingh 所说,要过滤列表(就像您在这里所做的那样),grep 应该是您选择的工具。 (另外值得一提的是,不带参数的split()split(/\s+/, $_) 相同。)
  • 一些more discussion关于这个话题。
【解决方案3】:

到目前为止,您的所有答案都是正确的,但它们似乎使事情变得比必要的困难得多。

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;

my @hex;
push @hex, /(0x[0-9a-f]+)/ig while <>;

$" = ',';
say "@hex";

这是作为 Unix 过滤器编写的(比硬编码文件名灵活得多),因此它从 STDIN 读取并写入 STDOUT。像这样称呼它:

$ ./extract_hex < your_input_txt

实际上可以进一步简化并丢失中间的@hex 数组。

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;

say join ',', map { /(0x[0-9a-f]+)/ig } <>;

但这对很多人来说可能有点太简洁了:-)

【讨论】:

  • Re “但他们似乎使事情变得比必要的困难得多。”,这与 4 小时前 Inferno 的回答几乎相同。不同之处在于您使用$"(没有将其本地化),就我而言,这对于投反对票来说已经足够糟糕了。
【解决方案4】:

下面的代码应该做你想做的事,其中 $input_filename 是数据所在文件的名称/路径,$output_filename 是你要写入数据的文件的名称/路径。永远记得使用严格;并使用警告;

#! /usr/bin/env perl

# Enforce good programming
use strict;
use warnings;

# Name of the file the data is in
my $input_filename  = 'input.txt';

# Name of the file you want to dump the output to
my $output_filename = 'output.txt';

# Open the file
open my $input_fh, "<", $input_filename or die $!;

# Array to store the hex data
my @hex_array;

# Loop over each of the lines of the file
while (my $line = <$input_fh>){
    # Find all the matches and push them to the array
    while ($line =~ m/(0x(?:[0-9]|[A-f])+)/gi){
        push @hex_array, $1;
    }
}

# Close the file
close $input_fh;

# Open the output file
open my $output_fh, ">", $output_filename or die $!;

# Write the data to the file
print {$output_fh} join(", ", @hex_array);

# Close the file
close $output_fh;

# Exit
exit();

【讨论】:

  • 谢谢。在这里,我想添加更多信息,我想提取仅以此大括号 {1} 开头的十进制值,例如 1。 pccpcch_rscp -47Sint8,signed char 。 2.fail_ind SUCCESS { 1} 我正在尝试使用 m/(0x(\-d+)(?:[0-9]|[A-f])+)/gi ..但它对我不起作用。请问帮帮我
  • @Abhishek:听起来你在问一个全新的问题。最好单独发布。
猜你喜欢
  • 2014-02-18
  • 2021-03-06
  • 1970-01-01
  • 2015-05-22
  • 1970-01-01
  • 1970-01-01
  • 2015-08-01
  • 2019-03-09
  • 1970-01-01
相关资源
最近更新 更多