By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,129 Members | 2,300 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,129 IT Pros & Developers. It's quick & easy.

Help - Counting text - Associative Array?

P: n/a
Greetings. I am trying to do something which should elementary for
Perl, but I have only been able to find bits and pieces on it. When I
put the bits together they do not work. Maybe I am going in the wrong
direction.

I want to count several strings of text in a file (security.txt) and
output the counts with a brief description of each. I have tried
specifying the descriptions (name) and the strings (exe) in the array
within the perl script. I can open the file to search ok, but the
counting/output doesn't work. It seems to count every line in the
file. The strings are not on their own lines in security.txt.

The goal is to see something like:

Name: Catalog Count:2
Name: Crime Count:1

Yes I am a newb, so if anyone can point me in the right direction I'd
sure appreciate it. TIA, Sam

print "\nSEARCHING...\n";

open (FILE, "security.txt");

print "\n";
###### Define names and their file paths ######

%exe = ( "Catalog", 'C:\Program Files\Internet Explorer\IEXPLORE.EXE',
"Crime", 'D:\crime\Reader\AcroRd32.exe');

###### Try to count the occurance of file paths ######

$count=0;

while(<FILE>) {

chomp;

#if ($_ = (values %exe)) {
$count++;
}

###### print names and counts #######

foreach $key (keys %exe) {

print "Name: $key\t Count: $count\n";

}

print "\nDONE.\n";

close(FILE);
Jul 19 '05 #1
Share this Question
Share on Google+
7 Replies


P: n/a
On Fri, 19 Mar 2004 at 16:59 GMT, Sam Lowry <mr******@hotmail.com> wrote:
direction.

I want to count several strings of text in a file (security.txt) and
output the counts with a brief description of each.


<OP's attempt snipped>
Not too bad after all. But this works:
#!/usr/bin/perl
use strict;
use warnings;

print "\nSEARCHING...\n\n";

my %exe = (
'C:\Program Files\Internet Explorer\IEXPLORE.EXE' => 'Catalog',
'D:\crime\Reader\AcroRd32.exe' => 'Crime',
);
my %count;

open (FILE, "security.txt");
while (<FILE>) {
chomp;
$count{$_}++ if exists $exe{$_};
}
close FILE;

print "Name: $exe{$_}\t Count: $count{$_}\n" foreach sort keys %exe;
print "\nDONE.\n";

__END__

security.txt would need to contain something like:

C:\Program Files\Internet Explorer\IEXPLORE.EXE
D:\crime\Reader\AcroRd32.exe
D:\crime\Reader\AcroRd32.exe
D:\crime\Reader\AcroRd32.exe

Jul 19 '05 #2

P: n/a
Roel van der Steen <ro*******@st2x.net> wrote in message news:<sl**********************@localhost.localdoma in>...
On Fri, 19 Mar 2004 at 16:59 GMT, Sam Lowry <mr******@hotmail.com> wrote:
direction.

I want to count several strings of text in a file (security.txt) and
output the counts with a brief description of each.


<OP's attempt snipped>
Not too bad after all. But this works:
#!/usr/bin/perl
use strict;
use warnings;

print "\nSEARCHING...\n\n";

my %exe = (
'C:\Program Files\Internet Explorer\IEXPLORE.EXE' => 'Catalog',
'D:\crime\Reader\AcroRd32.exe' => 'Crime',
);
my %count;

open (FILE, "security.txt");
while (<FILE>) {
chomp;
$count{$_}++ if exists $exe{$_};
}
close FILE;

print "Name: $exe{$_}\t Count: $count{$_}\n" foreach sort keys %exe;
print "\nDONE.\n";

__END__

security.txt would need to contain something like:

C:\Program Files\Internet Explorer\IEXPLORE.EXE
D:\crime\Reader\AcroRd32.exe
D:\crime\Reader\AcroRd32.exe
D:\crime\Reader\AcroRd32.exe


Dear Mr. van der Steen,

Thank you for your kind reply. Unfortunately, the strings are not
alone on their own lines in security.txt. I should have posted a
sample, thus:

3/15/2004,3:01:18 PM,Security,Success Audit,Object Access ,560,SERVER\
+refterm,SERVER,"Object Open:
Object Server: Security
Object Type: File
Object Name: C:\Program Files\Internet Explorer\IEXPLORE.EXE
New Handle ID: 536
Operation ID: {0,178316546}

3/15/2004,1:57:28 PM,Security,Success Audit,Object Access ,560,SERVER\
+Anon000,SERVER,"Object Open:
Object Server: Security
Object Type: File
Object Name: D:\crime\Reader\AcroRd32.exe
New Handle ID: 592
Operation ID: {0,177426959}

Your code shows me the logic and syntax, and I will study it to make
sure I understand what you did. The problem now is how to see the
array values in security.txt? Do I need to use regex or index
(mentioned elsewhere but which I know nothing about)?

- I just realized something: The context of the strings in
security.txt is always the same:

Object Name:[uniform space]$exe

If I include 'Object Name: ' with the C:\... as the complete value
in the array of my script it should work, no? Not the most elegant
solution but my eyes are already crossed after working on this having
had no formal training with Perl.

What is <the right way> to do this?

Thanks for reading.

Sam
Jul 19 '05 #3

P: n/a
On Sat, 20 Mar 2004 at 03:04 GMT, Sam Lowry <mr******@hotmail.com> wrote:
Roel van der Steen <ro*******@st2x.net> wrote in message news:<sl**********************@localhost.localdoma in>...
On Fri, 19 Mar 2004 at 16:59 GMT, Sam Lowry <mr******@hotmail.com> wrote:
> direction.
>
> I want to count several strings of text in a file (security.txt) and
> output the counts with a brief description of each.

Thank you for your kind reply. Unfortunately, the strings are not
alone on their own lines in security.txt. I should have posted a
sample, thus:


Yes, that's what I already suspected. But you didn't ask that, did you?
The best thing would be to change the algorithm a bit, but this time
I go for the minimal changes. Add

(my $search = join '|', keys %exe) =~ s/\\/\\\\/g;

before "my %count;" and change "$count{$_}++ if exists $exe{$_};" to

$count{$1}++ if /($search)/o;

But it's not very elegant now.
Jul 19 '05 #4

P: n/a
Roel van der Steen <ro*******@st2x.net> wrote in message news:<sl**********************@195-86-124-242.dsl.easynet.nl>...
On Sat, 20 Mar 2004 at 03:04 GMT, Sam Lowry <mr******@hotmail.com> wrote:
Roel van der Steen <ro*******@st2x.net> wrote in message news:<sl**********************@localhost.localdoma in>...
On Fri, 19 Mar 2004 at 16:59 GMT, Sam Lowry <mr******@hotmail.com> wrote:
> direction.
>
> I want to count several strings of text in a file (security.txt) and
> output the counts with a brief description of each.
Thank you for your kind reply. Unfortunately, the strings are not
alone on their own lines in security.txt. I should have posted a
sample, thus:


Yes, that's what I already suspected. But you didn't ask that, did you?


Yes, I did actually mention it originally, but I failed to give an
example and must take responsibility for being unclear. Het spijt me.
The best thing would be to change the algorithm a bit, but this time
I go for the minimal changes. Add

(my $search = join '|', keys %exe) =~ s/\\/\\\\/g;

before "my %count;" and change "$count{$_}++ if exists $exe{$_};" to

$count{$1}++ if /($search)/o;

But it's not very elegant now.

My main concern is that it works and also that I understand how it
works! I will get back to you after the weekend once I've had a
chance to study it/play with it.

Sincere thanks again for your efforts.

Sam
Jul 19 '05 #5

P: n/a
Dear Mr. van der Steen-

Your script works great. Would you please explain 2 lines to me:

(my $search = join '|', keys %exe) =~ s/\\/\\\\/g;

I think the text of the values belonging to the keys in the array is
being joined here but I don't understand the delimiting part =~
s/\\/\\\\/g. Please explain.

$count{$1}++ if /($search)/o;

Increase the count by 1 if the string is found in security.txt. How
does this work? What is if /($search)/o doing?

I want to fully understand your script so I can make 3 modifications:

1 - If a value is not found in security.txt I want $count=0. Right
now the result is blank and I get an error if warnings is turned on.

2 - The results are not sorted. The list is in a different order every
time despite foreach sort keys(%exe) in the print line.

3 - For neatness I'd like the counts to line up in a column rather
than just tab over from the key names.

Once I understand what you did I can try to achieve these things.

For your reference here's the whole script.

TIA Sam.

####Script###

use strict;
#use warnings;

print "\nSEARCHING...\n\n";

my %exe = (

'C:\Program Files\Internet Explorer\IEXPLORE.EXE' => 'Catalog',
'D:\crime\Reader\AcroRd32.exe' => 'Crime',

);

(my $search = join '|', keys %exe) =~ s/\\/\\\\/g;

my %count;

open (FILE, "security.txt");
while (<FILE>) {
chomp;

$count{$1}++ if /($search)/o;

}
close FILE;

print "Name: $exe{$_}\t Count: $count{$_}\n" foreach sort
keys(%exe);
print "\nDONE.\n";
Jul 19 '05 #6

P: n/a
On Wed, 24 Mar 2004 at 01:14 GMT, Sam Lowry <mr******@hotmail.com> wrote:
Dear Mr. van der Steen-

Your script works great. Would you please explain 2 lines to me:

(my $search = join '|', keys %exe) =~ s/\\/\\\\/g;
This builds a part of the regex. The pipe wil function as an
OR operator. All backslashes need to be escaped because they're
special in a regex (that's the s/\\/\\\\/g).

$count{$1}++ if /($search)/o;

Increase the count by 1 if the string is found in security.txt. How
does this work? What is if /($search)/o doing?
The slashes delimit the regex, the parentheses capture the
matched string to the special variable $1. The "o" modifier
tells the Perl compiler that this regex is not expected to
change during program execution (despite the fact that there
is a variable in the regex) and that the regex only needs to
be compiled once.

I want to fully understand your script so I can make 3 modifications:

1 - If a value is not found in security.txt I want $count=0. Right
now the result is blank and I get an error if warnings is turned on.
I'd guess you need to initialise the variables then. Now I
look at my own little program again, I indeed see a problem
there. There are two possibilities: print out all the strings
that is searched for, even if they are not found, or only print
the strings that have a count greater than zero. My sample is
just in between -- and indeed buggy.

2 - The results are not sorted. The list is in a different order every
time despite foreach sort keys(%exe) in the print line.
This is also a bug. The sort is on the keys of %exe, so that
would be on the full path names, instead of the shorthand names.

3 - For neatness I'd like the counts to line up in a column rather
than just tab over from the key names.
OK. Use Anno Siegel's Text::Table for that. It's not part of
the standard Perl installation, but if you have ActivePerl,
type "ppm install Text-Table" on the command prompt to install
it.

Once I understand what you did I can try to achieve these things.

For your reference here's the whole script.

TIA Sam.


As a 3rd try I propose something like this:
#!/usr/bin/perl
use strict;
use warnings;
use Text::Table;

print "\nSEARCHING...\n\n";

my %exe = (
Catalog => 'C:\Program Files\Internet Explorer\IEXPLORE.EXE',
Crime => 'D:\crime\Reader\AcroRd32.exe',
Foo => 'Bar',
);
my %count = map {$_, 0} keys %exe;

open FILE, "security.txt" or die $!;
while (<FILE>) {
while (my ($key, $value) = each %exe) {
$count{$key}++ if index($_, $value) > 0;
}
}
close FILE;

my $table = Text::Table->new(\'| ', 'Name', \' | ', 'Count', \' |');
$table->add($_, $count{$_}) foreach sort keys %count;
print $table->rule('-', '+'),
$table->title,
$table->rule('-', '+'),
$table->body,
$table->rule('-', '+');

print "\nDONE.\n";

__END__
Cheers, Roel
Jul 19 '05 #7

P: n/a
Roel van der Steen <ro*******@st2x.net> wrote in message news:<sl**********************@195-86-124-242.dsl.easynet.nl>...
On Wed, 24 Mar 2004 at 01:14 GMT, Sam Lowry <mr******@hotmail.com> wrote:
Dear Mr. van der Steen-

Your script works great. Would you please explain 2 lines to me:

(my $search = join '|', keys %exe) =~ s/\\/\\\\/g;


This builds a part of the regex. The pipe wil function as an
OR operator. All backslashes need to be escaped because they're
special in a regex (that's the s/\\/\\\\/g).

Yeah, but you forgot to quote the .

This is more effectively and more readably done as

my $search = join '|', map { quotemeta } keys %exe;

$count{$1}++ if /($search)/o;

Increase the count by 1 if the string is found in security.txt. How
does this work? What is if /($search)/o doing?


The "o" modifier
tells the Perl compiler that this regex is not expected to
change during program execution (despite the fact that there
is a variable in the regex) and that the regex only needs to
be compiled once.

The /o qualifier is dangerous - one day you may extend your program
such that $searh does change.

Much better to get into the habit of simply explicitly taking the
regex compliation outside the loop.

$search = qr/($search)/;

Note that IIRC even if you don't use qr// or /o the regex will still
only be compiled once so long as $search doesn't change.

This newsgroup does not exist (see FAQ). Please do not start threads
here.
Jul 19 '05 #8

This discussion thread is closed

Replies have been disabled for this discussion.