如何从perl中的关键字主要数组拆分中获取不同数组中的值?

时间:2015-03-18 13:30:47

标签: perl

我有一个字符串FORCE=(1,10,A,11,20,D,31,5,BI,A,36,9,NU,D,46,9,D) 我想使用perl在找到A / D时将这些值存储在不同的数组中。 例如

Array1=1,10,A

Array2=11,20,D

Array3=31,5,BI,A

Array4=36,9,NU,D

Array5=46,9,D

  

不知道这一堆是3或4个值!


目前我正在使用split

拆分数组
#!/usr/bin/perl

use strict;
use warnings;

@main = "FORCE=(1,10,A,11,20,D,31,5,BI,A,36,9,NU,D,46,9,D)";
my @val = split(/,/,$1);
print "Val Array = @val\n";

但如何进一步前进?

7 个答案:

答案 0 :(得分:3)

# Grab the stuff inside the parens.
my $input      = "FORCE=(1,10,A,11,20,D,31,5,BI,A,36,9,NU,D,46,9,D)";
my ($vals_str) = $input =~ /\(([^)]+)\)/;

# Get substrings of interest.
my @groups = $vals_str =~ /[^,].+?,[AD](?=,|$)/g;

# Split those into your desired arrays.
my @forces = map [split /,/, $_], @groups;

请注意,这种基于正则表达式的方法适用于您可以认为输入数据相当干净的情况。如果您需要处理更混乱的数据并需要您的代码来执行验证,我建议您考虑不同的解析策略(如其他答案中所建议的那样)。

答案 1 :(得分:1)

my $str = 'FORCE=(1,10,A,11,20,D,31,5,BI,A,36,9,NU,D,46,9,D)';

my ($list) = $str =~ /^[^=]*=\(([^()]*)\)$/
   or die("Unexpected format");

my @list = split(/,/, $list);

my @forces;
while (@list) {
   my @force;
   while (1) {
      die('No "A" or "D" value found') if !@list;
      push @force, shift(@list);
      last if $force[-1] eq 'A' || $force[-1] eq 'D';
   }

   push @forces, \@force;
}

结果:

@{$forces[0]} = (  1, 10, 'A' );
@{$forces[1]} = ( 11, 20, 'D' );
@{$forces[2]} = ( 31,  5, 'BI', 'A' );
@{$forces[3]} = ( 36,  9, 'NU', 'D' );
@{$forces[4]} = ( 46,  9, 'D' );

答案 2 :(得分:1)

#!/usr/bin/perl

use strict;
use warnings;
use List::MoreUtils 'part';

# Grab the stuff inside the parens.
my $input = "FORCE=(1,10,A,11,20,D,31,5,BI,A,36,9,NU,D,46,9,D)";
my ($vals_str) = $input =~ /\(([^)]+)\)/;
my @val = split(/,/,$vals_str);
print "Val Array = @val\n";
my $i = 0;
my @partitions = part { $_ eq 'A' || $_ eq 'D' ? $i++ : $i } @val;

创建一个数组@partitions,其中每个元素都是对一个数组的引用,该数组包含您想要分组的3或4个元素。

答案 3 :(得分:1)

让我们从一些问题开始:

@main = "FORCE=(1,10,A,11,20,D,31,5,BI,A,36,9,NU,D,46,9,D)";

您有use strict,但首先您永远不会声明@main,而@main是一个数组,但您只需为其分配一个字符串。

my @val = split(/,/,$1);

$1来自哪里?

print "Val Array = @val\n";

这实际上可行。如果@val中有任何内容。

你有:

Array1=1,10,A
Array2=11,20,D
Array3=31,5,BI,A
Array4=36,9,NU,D
Array5=46,9,D

如您所期望的结果。这些标量变量,还是这些子数组?

我将假设以下内容:

  • 您需要将FORCE字符串转换为数组。
  • 您需要各种阵列的结果。

因此,我将使用数组数组,这意味着我将使用References

#! /usr/bin/env perl

use strict;
use warnings;
use feature qw(say);

# Convert the string into an array
my $force = "FORCE=(1,10,A,11,20,D,31,5,BI,A,36,9,NU,D,46,9,D)";
$force =~ s/FORCE=\((.*)\)/$1/;    # Remove the "FORCE=(" prefix and the ")" suffix
my @main = split /,/, $force;      # Convert string into an array

my @array_of_arrays;               # Where I'm storing the arrays of arrays
my $array_of_arrays_number = 0;    # Array number I'm using for @arrays

while (@main)  {      # Going through my "@main" array one character at a time

    # Take a character from the @main array and put it onto whatever array of arrays you're pushing items into
    my $character = shift @main;
    push @{ $array_of_arrays[$array_of_arrays_number] }, $character;

    # If Character is 'A' or 'D', start a new array_of_arrays
    if ( $character eq 'A' or $character eq 'D' ) {
        $array_of_arrays_number += 1;
    }
}

# Let's print out these arrays
for my $array_number ( 0..$#array_of_arrays ) {
    say "Array$array_number = ", join ", ", @{ $array_of_arrays[$array_number] };
}

答案 4 :(得分:0)

我喜欢功能方法,所以有一个版本首先制作拼接索引,然后生成子阵列数组

use strict;
use warnings;
use Carp;

sub splice_force ($) {
    my $str = shift;
    croak "Unexpected format" unless $str =~ /^FORCE=\(([^()]*)\)/;
    my @list = split ',', $1;

    # find end positions for each splice
    my @ends = grep $list[$_] =~ /^[AD]$/, 0 .. $#list;

    # make array with starting positions
    my @starts = ( 0, map $_ + 1, @ends );

    #finally make splices (ignore last @starts element so iterate by @ends)
    map [ @list[ shift(@starts) .. $_ ] ], @ends;
}

my $str = 'FORCE=(1,10,A,11,20,D,31,5,BI,A,36,9,NU,D,46,9,D)';

print "@$_\n" for splice_force $str;

答案 5 :(得分:0)

您可以在不创建中间数组的情况下执行此操作:

#!/usr/bin/env perl

use strict;
use warnings;

my $input = q{FORCE=(1,10,A,11,20,D,31,5,BI,A,36,9,NU,D,46,9,D)};
my @groups = ([]);

while ($input =~ / ([A-Z0-9]+) ( [,)] ) /xg) {
    my ($token, $sep) = ($1, $2);
    push @{ $groups[-1] }, $token;
    $token =~ /\A(?:A|D)\z/
        or next;
    $sep eq ')'
        and last;
    push @groups, [];
}

use YAML::XS;
print Dump \@groups;

输出:

---     
- - '1' 
  - '10'
  - A   
- - '11'
  - '20'
  - D   
- - '31'
  - '5' 
  - BI  
  - A   
- - '36'
  - '9' 
  - NU  
  - D   
- - '46'
  - '9' 
  - D

答案 6 :(得分:0)

除了split之外,不需要任何其他内容。此解决方案检查字符串是否具有预期形式,并提取括号之间的字符。然后将其拆分为逗号,前面是包含AD的字段,结果将在逗号上再次拆分。

use strict;
use warnings;
use 5.014;    # For \K regex pattern

my $str = 'FORCE=(1,10,A,11,20,D,31,5,BI,A,36,9,NU,D,46,9,D)';

my @parts;
if ( $str =~ /FORCE \s* = \s* \( ( [^)]+ ) \)/x ) {
  @parts = map [ split /,/ ], split / [AD] [^,]* \K , /x, $1;
}

use Data::Dump;
dd \@parts;

<强>输出

[
  [1, 10, "A"],
  [11, 20, "D"],
  [31, 5, "BI", "A"],
  [36, 9, "NU", "D"],
  [46, 9, "D"],
]