Help - Counting text - Associative Array?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Sam Lowry

    Help - Counting text - Associative Array?

    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\IEXPLO RE.EXE',
    "Crime", 'D:\crime\Reade r\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);
  • Roel van der Steen

    #2
    Re: Help - Counting text - Associative Array?

    On Fri, 19 Mar 2004 at 16:59 GMT, Sam Lowry <mr_lowry@hotma il.com> wrote:[color=blue]
    > direction.
    >
    > I want to count several strings of text in a file (security.txt) and
    > output the counts with a brief description of each.[/color]

    <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\IEXPLO RE.EXE' => 'Catalog',
    'D:\crime\Reade r\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\IEXPLO RE.EXE
    D:\crime\Reader \AcroRd32.exe
    D:\crime\Reader \AcroRd32.exe
    D:\crime\Reader \AcroRd32.exe

    Comment

    • Sam Lowry

      #3
      Re: Help - Counting text - Associative Array?

      Roel van der Steen <roel-perl@st2x.net> wrote in message news:<slrnc5mbi d.284.roel-perl@localhost. localdomain>...[color=blue]
      > On Fri, 19 Mar 2004 at 16:59 GMT, Sam Lowry <mr_lowry@hotma il.com> wrote:[color=green]
      > > direction.
      > >
      > > I want to count several strings of text in a file (security.txt) and
      > > output the counts with a brief description of each.[/color]
      >
      > <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\IEXPLO RE.EXE' => 'Catalog',
      > 'D:\crime\Reade r\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\IEXPLO RE.EXE
      > D:\crime\Reader \AcroRd32.exe
      > D:\crime\Reader \AcroRd32.exe
      > D:\crime\Reader \AcroRd32.exe[/color]

      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,Suc cess Audit,Object Access ,560,SERVER\
      +refterm,SERVER ,"Object Open:
      Object Server: Security
      Object Type: File
      Object Name: C:\Program Files\Internet Explorer\IEXPLO RE.EXE
      New Handle ID: 536
      Operation ID: {0,178316546}

      3/15/2004,1:57:28 PM,Security,Suc cess 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

      Comment

      • Roel van der Steen

        #4
        Re: Help - Counting text - Associative Array?

        On Sat, 20 Mar 2004 at 03:04 GMT, Sam Lowry <mr_lowry@hotma il.com> wrote:[color=blue]
        > Roel van der Steen <roel-perl@st2x.net> wrote in message news:<slrnc5mbi d.284.roel-perl@localhost. localdomain>...[color=green]
        >> On Fri, 19 Mar 2004 at 16:59 GMT, Sam Lowry <mr_lowry@hotma il.com> wrote:[color=darkred]
        >> > direction.
        >> >
        >> > I want to count several strings of text in a file (security.txt) and
        >> > output the counts with a brief description of each.[/color]
        >>[/color][/color]
        [color=blue]
        > 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:[/color]

        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.

        Comment

        • Sam Lowry

          #5
          Re: Help - Counting text - Associative Array?

          Roel van der Steen <roel-perl@st2x.net> wrote in message news:<slrnc5nus 1.3kv.roel-perl@195-86-124-242.dsl.easynet .nl>...[color=blue]
          > On Sat, 20 Mar 2004 at 03:04 GMT, Sam Lowry <mr_lowry@hotma il.com> wrote:[color=green]
          > > Roel van der Steen <roel-perl@st2x.net> wrote in message news:<slrnc5mbi d.284.roel-perl@localhost. localdomain>...[color=darkred]
          > >> On Fri, 19 Mar 2004 at 16:59 GMT, Sam Lowry <mr_lowry@hotma il.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.
          > >>[/color][/color]
          >[color=green]
          > > 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:[/color]
          >
          > Yes, that's what I already suspected. But you didn't ask that, did you?[/color]

          Yes, I did actually mention it originally, but I failed to give an
          example and must take responsibility for being unclear. Het spijt me.
          [color=blue]
          > 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.[/color]


          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

          Comment

          • Sam Lowry

            #6
            Re: Help - Counting text - Associative Array? (van_der_Steen)

            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\IEXPLO RE.EXE' => 'Catalog',
            'D:\crime\Reade r\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" ;

            Comment

            • Roel van der Steen

              #7
              Re: Help - Counting text - Associative Array? (van_der_Steen)

              On Wed, 24 Mar 2004 at 01:14 GMT, Sam Lowry <mr_lowry@hotma il.com> wrote:[color=blue]
              > Dear Mr. van der Steen-
              >
              > Your script works great. Would you please explain 2 lines to me:
              >
              > (my $search = join '|', keys %exe) =~ s/\\/\\\\/g;[/color]

              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).
              [color=blue]
              >
              > $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?[/color]

              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.
              [color=blue]
              >
              > 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.[/color]

              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.
              [color=blue]
              >
              > 2 - The results are not sorted. The list is in a different order every
              > time despite foreach sort keys(%exe) in the print line.[/color]

              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.
              [color=blue]
              >
              > 3 - For neatness I'd like the counts to line up in a column rather
              > than just tab over from the key names.[/color]

              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.
              [color=blue]
              >
              > Once I understand what you did I can try to achieve these things.
              >
              > For your reference here's the whole script.
              >
              > TIA Sam.
              >[/color]

              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\IEXPLO RE.EXE',
              Crime => 'D:\crime\Reade r\AcroRd32.exe' ,
              Foo => 'Bar',
              );
              my %count = map {$_, 0} keys %exe;

              open FILE, "security.t xt" 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

              Comment

              • nobull@mail.com

                #8
                Re: Help - Counting text - Associative Array? (van_der_Steen)

                Roel van der Steen <roel-perl@st2x.net> wrote in message news:<slrnc633s c.h76.roel-perl@195-86-124-242.dsl.easynet .nl>...[color=blue]
                > On Wed, 24 Mar 2004 at 01:14 GMT, Sam Lowry <mr_lowry@hotma il.com> wrote:[color=green]
                > > Dear Mr. van der Steen-
                > >
                > > Your script works great. Would you please explain 2 lines to me:
                > >
                > > (my $search = join '|', keys %exe) =~ s/\\/\\\\/g;[/color]
                >
                > 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).
                >[/color]
                Yeah, but you forgot to quote the .

                This is more effectively and more readably done as

                my $search = join '|', map { quotemeta } keys %exe;
                [color=blue][color=green]
                > >
                > > $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?[/color]
                >
                > 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.[/color]


                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.

                Comment

                Working...