0

I want to report the number of times a character occurs in a string. Thanks to Is there a better way to count occurrence of char in a string?, the first part of the following works elegantly.

#!/usr/bin/env perl
use strict; use warnings;
my $string='dog
#
####
pig horse';
# https://stackoverflow.com/questions/34437248/is-there-a-better-way-to-count-occurrence-of-char-in-a-string
print join('','# occurs ',my$dummy=()=$string=~/[#]/g,' times in',"\n",$string,"\n",);

# the following yields no count at all:
print join('','# occurs ',()=$string=~/[#]/g,' times in',"\n",$string,"\n",);

Is there a way to eliminate the seemingly gratuitous declaration of the $dummy variable? I'd like to use that integer directly in join without first declaring a variable to grab the value.

Jacob Wegelin
  • 1,174
  • 10
  • 15

1 Answers1

4

That trick

$dummy = () = $string =~ /[#]/g

works because the whole assignment-expression

() = EXPR

itself is in a scalar context, being assigned to a scalar ($dummy), so it returns the length of the would-be list which EXPR returns (it being in list context).

So impose the scalar context on it

say join('', '# occurs ', scalar( () = $string =~ /#/g ),' times');

I've shortened the string for easier reading, and employed say instead of print ... "\n".

See this page for more on () = EXPR and its context, and the links in it.

Not sure that this is really much prettier but it does what is asked.

But if you really always want just one character's count than tr does it much more nicely

print join('', '# occurs ', $string =~ tr/#//,' times in',"\n",$string,"\n",);

If one were to really just print then there is no need to form a string with join '' since print takes a list and effectively concatenates elements without anything in between, so joins them

say '# occurs ', scalar( () = $string =~ /#/g ), " times in\n", $string;

or, for a single character

say '# occurs ', $string =~ tr/#//, ' times in', "\n", $string;

(But I take it that the print is just an example for this question and that you really need a string...)

zdim
  • 56,772
  • 4
  • 49
  • 75
  • @JacobWegelin This has been closed, perhaps rightly, but I've still edited and added a little, what you may want to quickly check out – zdim Nov 18 '21 at 18:20
  • Your answer is very helpful. But what is the would-be list of which we find the length? Is there a way to print out this list using Dumper, perhaps? What are its components? I don't understand how the regex expression creates a list (or array). – Jacob Wegelin Nov 21 '21 at 10:44
  • 1
    @JacobWegelin In Perl, how operators work depends on context they're in. A regex's match is a great example -- in scalar context (when assigned to a scalar or inside a condition etc) it returns true/false (normally `1`/`''`) but in "list context" (when assigned to an array for instance) it returns the actual matches. That `/#/g` returns a list of all `#` in what is matched, in list context. (Not very useful, but `/\w+/g` returns a list of all words in the string it matches -- better!) So if you want to see the matches assign to an actual array (instead of `()`) so to keep them ... – zdim Nov 24 '21 at 06:37
  • 1
    @JacobWegelin [cont'd] like `say '# occurs ', scalar( @m = $string =~ /#/g ), ' times'; say "@m";`. So here the matches from `$string` (all `#`s in it) are assigned to `@m` (instead of being flattened into nothingness with `()`) so `@m` has elements `#, #,...` (as many as there are in `$string`) – zdim Nov 24 '21 at 06:38
  • 1
    (the above surely has much that you know but I state all that for completeness) – zdim Nov 24 '21 at 06:39
  • 1
    A nicer example: `perl -wE'$s=q(hi ho ye); say "There are ", scalar( @w = $s =~ /\w+/g ), " words in $s"; say for @w'` (copy-paste and run on the command-line) – zdim Nov 24 '21 at 06:47
  • I did not know these things and this is extremely helpful. You are a good teacher. – Jacob Wegelin Dec 10 '21 at 15:14
  • @JacobWegelin Thank you for saying that :) I'm glad it helped (when I looked over it after the fact ... I would've written them better; I often wish I could edit comments. But the example is good I think.) Let me know if more comes up – zdim Dec 28 '21 at 07:49