Counting the number of occurances of all characters (a-z) in a string

Hi,

I am trying out different scripts in PERL. I want to take a line/string as an input from the user and count the number of occurrances of all the alphabets (a..z) in the string. I tried doingit like this :

#! /opt/exp/bin/perl

print "Enter a string or line : ";
$string = <STDIN>;
chop $string;
$string =~ tr/[A-Z]/[a-z]/;
#print @string;
print "\n";
@arr = ('a' .. 'z');
foreach $val (@arr)
{
$count = ($string =~ tr/$val//);
print "$val occurred $count times\n";
}

But looks like I am going wrong somewhere. Please guide me to solve this.

Regards,
Sendhil

If it can be done in shell script:

while true
do
 echo "Enter string:"
 read mInp
 mCnt=`echo $mInp | egrep -c '[a-zA-Z]'`
 if [ "$mCnt" = "1" ]; then
   echo "Found letters"
 fi
done

rsendhilmani,

This had me puzzled for a while, but I think I figured out what is wrong. I found this

So the tr command is trying to translate the letters "$", "v", "a", and "l", not the value that $val contains.

Try

eval "\$count = (\$string =~ tr/$val//)";

Or use the s/// instead

$count = $string =~ s/$val//g;

Not trying to win any awards for maintainability... :slight_smile:

#!/usr/bin/perl
#
# count.pl
#

use strict;
use warnings;

my $char;
my %chars=();

print "Enter a line: ";

while( $char = getc() ) {
  last if( $char =~ /\n/ );
  $chars{ $char }++;
}

my @keys = sort keys( %chars );
foreach my $key (@keys) {
  print "$key = $chars{ $key }\n";
}
$ perl count.pl
Enter a line: This is a test
  = 3
T = 1
a = 1
e = 1
h = 1
i = 2
s = 3
t = 2

Hi,

Thanks a lot. It worked :slight_smile:

I know this is an older thread, but I had a slightly different scenario, where I needed non-destructive counting and thought I'd share.

The s///g and tr/// methods already mentioned remove text from the original string. With a slight modification (adding parentheses and $1), the s/// operator can be used non-destructively:

$count = $string =~ s/([a-zA-Z])/$1/g;

In my specific case, I needed to sort a list of directories by depth. That is: /, /onelevel, /two/levels, /three/level/path, etc.

My solution was the following:

@dirs = sort {($a =~s/(\/)/$1/g) <=> ($b =~s/(\/)/$1/g)} @dirs;

It sorts the list by the number of times "/" appears in the directory, which (on a Unix system) is the same as the depth. The sort function is able to obtain the counts repeatedly and still have the original strings left over.

Note that my code doesn't correctly handle doubled slashes (e.g. "/my//dir") or relative paths (e.g., "../dir" or "/my/dir/../dir2"), but it's easy to handle those by ensuring that the paths are all absolute prior to the above line of code.