开发者

Perl Array Question

Never done much programming -- been charged at work with manipulating the data开发者_开发技巧 from comment cards. Using perl so far I've got the database to correctly put its daily comments into an array. Comments are each one LINE of text within the database, so I just split the array on the line-break.

my @comments = split("\n", $c_data);

And yes, this being my first time programming, that took me wayyy too long to figure out.

At this point I now need to organize these array elements (is that what I should call them?) into their own separate scalars based on capitalized words (this is a behavior of the database, which was at one point corrupt).

Example of what two elements of the array look like:

print "$comments[0]\n";
This dining experience was GOOD blah blah blah.

or

print "$comments[1]\n";
Overall this was a BAD time and me and my blah blah.

These "good" or "bad" or "best" are already capitalized by the database the data came from.

What's the easiest way in Perl to get these lines into scalars from an array based on these capitalized words?


If I understand you correctly, you want to merge array elements that match a certain word. You can do it like this:

my @bad_comments = grep { /\bBAD\b/ } @comments;
my @good_comments = grep { /\bGOOD\b/ } @comments;

That way all 'good' and 'bad' comments go to each own array.

Now if you need to merge them into a scalar you'd want to join them (opposite of split):

my $bad_comments  = join "\n", grep { /\bBAD\b/ } @comments;
my $good_comments = join "\n", grep { /\bGOOD\b/ } @comments;


Think hash table when you want to group data by arbitrary string keys. In this case, you have an array of GOOD comments and an array of BAD comments. What if you had an array of SO-SO comments? A strategy based on having array variables @good, @bad, @soso breaks down fast.

You have some ways to go before you can fully understand the code below:

#!/usr/bin/perl

use strict; use warnings;

use Regex::PreSuf;

my %comments;

my @types = qw( GOOD BAD ); # DRY
my $types_re = presuf @types;

while ( my $comment = <DATA> ) {
    chomp $comment;
    last unless $comment =~ /\S/;

    # capturing match in list context returns captured strings
    my ($type) = ( $comment =~ /($types_re)/ );
    push @{ $comments{$type} }, $comment;
}

for my $type ( @types ) {
    print "$type comments:\n";

    for my $comment ( @{ $comments{$type} } ) {
        print $comment, "\n";
    }
}

__DATA__
This dining experience was GOOD blah blah blah.
Overall this was a BAD time and me and my blah blah.


You could use regular expressons, eg:

if ($comments[$i] =~ /GOOD/) {
    # good comment
}

or more generally

if ($comments[$i] =~ /\b([A-Z]{2,})\b/) {
    print "Comment: $1\n";
}

Here, \b means word boundary, () are used to extract captured text, [A-Z] represent a group of capital characters - capital letters, {2,} means that there have to be 2 or more characters defined by previous class.


I would store all your comments into a hash-of-arrays data structure, with the key being your capitalized word. Here is a general solution to grab any capitalized word (assuming only one per comment), not just GOOD and BAD:

use strict;
use warnings;

my @comments = <DATA>;
chomp @comments;

my %data;
for (@comments) {
    my $cap;    
    for (split) {
        $cap = $_ if /^[A-Z]+$/;
    }
    if ($cap) { push @{ $data{$cap} }, $_ }
}
use Data::Dumper; print Dumper(\%data);

__DATA__
This is GOOD stuff
Here's some BAD stuff.
More of the GOOD junk.
Nothing here.

Here is the output:

$VAR1 = {
          'BAD' => [
                     'Here\'s some BAD stuff.'
                   ],
          'GOOD' => [
                      'This is GOOD stuff',
                      'More of the GOOD junk.'
                    ]
        };


In my opinion, your best bet would be to create a disk-based database of some sort (SQLite?) that stores the comments and type as separate data.

Then use one of the other posted solutions to import your existing data into it.

The only problem here is that you need to learn Perl's DBI layer and a bit of SQL to use SQLite with Perl.


Not sure what you mean by "organize" and "based on".

If you mean produce a list of any capitalized words, each with a list of the lines containing that word (similar to toolic's solution, you could do this:

my %CAPS = ();

map {
    my ($word) = /(\b[A-Z]+\b)/;
    push( @{ $CAPS{$word} }, $_)
} @comments;

This will build a mapping of WORDS to things, and the things in this case are going to be lists of lines.

And you can refer to these lists as $CAPS{'GOOD'} or $CAPS{'BAD'}, or $CAPS{whatever}.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜