Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot

Regex - counting number of '|'

by perl_junkie (Acolyte)
on Mar 17, 2008 at 20:42 UTC ( #674640=perlquestion: print w/replies, xml ) Need Help??
perl_junkie has asked for the wisdom of the Perl Monks concerning the following question:

Hello monks.. I had a question about counting the number of occurences of '|' in an input row. I am having to hardcode this symbol in the code in order for it to work properly. When I tried to pass this symbol in a variable, it didnt work. Can you please help me out with this? The code is below. The statement in comment is what I used previously.
#!/usr/bin/perl use Fcntl; #The Module use strict; #my $inp_row="per|l|mo|nks|ro|ck|s"; my $de='|'; print "delim is $de"; #my $count = ($inp_row =~ tr/|//); my $count = ($inp_row =~ tr/$de//); print "count is $count\n";
This is probably elementary stuff for u guys out there... sorry !! Thanks!!!!

Replies are listed 'Best First'.
Re: Regex - counting number of '|'
by FunkyMonk (Chancellor) on Mar 17, 2008 at 21:06 UTC
    Or, using m// instead of tr and the infamous =()= operator.
    my $inp_row="per|l|mo|nks|ro|ck|s"; my $de = "|"; my $count =()= $inp_row =~ m/\Q$de/g; print "Delimeter is '$de', count is $count\n"; #Output: #Delimeter is '|', count is 6

      Hi, I had one more question -

      I have to use the split command on the same file to split each input record on its delimiters and and assign it to an array. I am trying to use eval here also (as specified above), but, it is throwing an error. One of the error msg is
      "Bareword "per" not allowed while "strict subs" in use at (eval 2) line 1."

      #!/usr/bin/perl use Fcntl; use strict; print "starting script..."; my $inp_row = "per|l|mo|nks|rock|s"; my $de = '|'; my @cl_data_row; my $count = (eval "\$inp_row =~ tr/$de//"); die $@ if $@; print "count is $count\n"; chop($inp_row); #@cl_data_row=split(/\|/,$inp_row); @cl_data_row=(eval"\split(/\$de/,$inp_row)"); for (my $x=0;$x<$count;$x++) { print "row element is $cl_data_row[$x]\n"; }
      Thanks for your help!!!

        $cl_data_row[$x] is unpopulated but no error here under Ubuntu & 5.8.7 with your script:

        ww@GIG:~/pl_test$ perl -c syntax OK ww@GIG:~/pl_test$ perl starting script...count is 5 row element is row element is row element is row element is row element is ww@GIG:~/pl_test$

        Your line 17 isn't doing what you want/expect. @cl_data_row remains undef Compare:

        (Replaces your 17) my $cl_data_row=(\split(/\$de/,$inp_row)); (added) print "\$cl_data_row is $$cl_data_row\n";

        from which the output is:

        ww@GIG:~/pl_test$ perl starting script...count is 5 $cl_data_row is per|l|mo|nks|rock|s

        BTW, your chop in line 15 isn't doing what I suspect you think: it's removing the last character, the "s" in "rock|s"


        has four errors in it!

        • \s should be just s.
        • Shouldn't be interpolating $inp_row. (Escape the $.)
        • That leaves no reason to use eval.
        • You didn't convert the contents of $de from text to a regexp.


        @cl_data_row = split(/\Q$de/, $inp_row);

        Why aren't you using Text::CSV anyway?

        Oh and the tr/// line

        my $count = (eval "\$inp_row =~ tr/$de//");

        has a problem too. The contents of $de aren't properly converted from text to a tr/// search list. It happens to work for "|", but it won't work for arbitrary seperator characters which seems to be your goal. Fixed:

        my $count = (eval "\$inp_row =~ tr/\Q$de\E//");

        The following is much simpler, though:

        my $count =()= $inp_row =~ /\Q$de\E/g;
        #!/usr/bin/perl use strict; use warnings; use Data::Dumper; # No need to double quoted my $inp_row = q{per|l|mo|nks|ro|ck|s}; my $de = q{|}; my $count = 0; my $row; $count++ for $inp_row =~ /\Q$de/g; print "Delim: $de\nCount: $count\n"; push @{$row}, split /\Q$de/, $inp_row; print Dumper $row;
        Output: Delim: | Count: 6 $VAR1 = [ 'per', 'l', 'mo', 'nks', 'ro', 'ck', 's' ];



        'Ebry haffa hoe hab im tik a bush'. Jamaican proverb
Re: Regex - counting number of '|'
by kyle (Abbot) on Mar 17, 2008 at 20:52 UTC

    This is documented in perlop:

    Because the transliteration table is built at compile time, neither the SEARCHLIST nor the REPLACEMENTLIST are subjected to double quote interpolation. That means that if you want to use variables, you must use an eval():
    eval "tr/$oldlist/$newlist/"; die $@ if $@;

    In your case, this would be:

    my $count = (eval "\$inp_row =~ tr/$de//"); die $@ if $@;
Re: Regex - counting number of '|'
by Fletch (Chancellor) on Mar 17, 2008 at 20:48 UTC

    tr doesn't do double quote interpolation, and this is documented. If you want it you've got to use eval:

    my $count; eval qq{ \$count = \$inp_row =~ tr/$de/$de/; }; die "Problem in eval'd tr: $@\n";

    Update: Bah, that wasn't directly to it. Direct link to the relevant section in perlop: tr///. Specifically you want the paragraph starting "Because the transliteration table is built at compile time . . .".

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: Regex - counting number of '|'
by toolic (Bishop) on Mar 17, 2008 at 20:53 UTC
    One way to do it:
    #!/usr/bin/env perl use warnings; use strict; my $inp_row = "per|l|mo|nks|ro|ck|s"; my $de = '|'; my @chars = split //, $inp_row; my $cnt = 0; for (@chars) { $cnt++ if ($_ eq $de) } print "delim is $de count is $cnt\n";


    delim is | count is 6
      my @chars = split //, $inp_row; my $cnt = 0; for (@chars) { $cnt++ if ($_ eq $de) }

      You could eliminate the array, for loop and conditional increment by using grep.

      my $cnt = grep { $_ eq $de } split m{}, $inp_row;

      I hope this is of interest.



      This is awesome guys..!!! works like a charm...!!

      Thanks a lot Kyle, Toolic....!

Re: Regex - counting number of '|'
by mickeyn (Priest) on Mar 18, 2008 at 07:42 UTC
    this one works for me:

    use strict; my $inp_row = "per|l|mo|nks|ro|ck|s"; print $inp_row =~ tr/\|/\|/, "\n";
      He specifically said he didn't want to hardcode the character, so no good.
        Hi guys!

        Thanks a lot for takin the time out for this...!! I m really grateful...!! I am new to perl and was havin a really tough time with these things... but things are now slowly falling into place....!!

        Again... thanks..!!

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://674640]
Approved by toolic
and cookies bake in the oven...

How do I use this? | Other CB clients
Other Users?
Others taking refuge in the Monastery: (6)
As of 2018-03-21 21:00 GMT
Find Nodes?
    Voting Booth?
    When I think of a mole I think of:

    Results (270 votes). Check out past polls.