3

I want to make all the consonants in a word uppercase:

> my $word = 'camelia'
camelia
> $word ~~ s:g/<-[aeiou]>/{$/.uc}/
(「c」 「m」 「l」)
> $word
CaMeLia

To make the code more general, I store the list of all the consonants in a string variable

my $vowels = 'aeiou';

or in an array

my @vowels = $vowels.comb;

How to solve the original problem with $vowels or @vowels variables?

Eugene Barsky
  • 5,780
  • 3
  • 17
  • 40

3 Answers3

3

Maybe the trans method would be more appropriate than the subst sub or operator.

Try this:

my $word = "camelia";
my @consonants = keys ("a".."z") (-) <a e i o u>;
say $word.trans(@consonants => @consonants>>.uc);
# => CaMeLia
timotimo
  • 4,299
  • 19
  • 23
  • Thanks! It's indeed much easier in this case. Do I understand correctly that `(-)` coerces the two lists to sets and `keys` makes the result of set subtraction a list? – Eugene Barsky Nov 07 '17 at 08:00
  • 1
    yes, that's exactly what happens. could have done it any number of ways, but this one was the simplest i could come up with :) – timotimo Nov 08 '17 at 00:08
3

With the help of moritz's explanation, here is the solution:

my constant $vowels = 'aeiou';
my regex consonants {
    <{
       "<-[$vowels]>"
     }>
}

my $word = 'camelia';
$word ~~ s:g/<consonants>/{$/.uc}/;
say $word;  # CaMeLia
Eugene Barsky
  • 5,780
  • 3
  • 17
  • 40
  • 2
    This can also be done inline as well: `/<{"<-[$vowels]>"}>/` [Try it online](https://tio.run/##K0gtyjH7/z@3UiE5P6@4JDGvREGlLL88NadYwVZBPTE1M79U3ZqLCyivUp5flAISTE7MTc3JTAQKQ4Tq6hSKrdL1baqVbHSjoZpj7ZRq7fSrVfT1SpNr9a25ihOhBlj//w8A "Perl 6 – Try It Online") – primo Feb 26 '19 at 08:32
2

You can use <!before …> along with <{…}>, and . to actually capture the character.

my $word = 'camelia';
$word ~~ s:g/

  <!before         # negated lookahead
    <{             # use result as Regex code
      $vowel.comb  # the vowels as individual characters
    }>
  >

  .                # any character (that doesn't match the lookahead)

/{$/.uc}/;
say $word;         # CaMeLia

You can do away with the <{…}> with @vowels

I think it is also important to realize you can use .subst

my $word = 'camelia';
say $word.subst( :g, /<!before @vowels>./, *.uc ); # CaMeLia
say $word;                                         # camelia

I would recommend storing the regex in a variable instead.

my $word = 'camelia'
my $vowel-regex = /<-[aeiou]>/;

say $word.subst( :g, $vowel-regex, *.uc ); # CaMeLia

$word ~~ s:g/<$vowel-regex>/{$/.uc}/;
say $word                                  # CaMeLia
Brad Gilbert
  • 33,846
  • 11
  • 78
  • 129
  • Thanks for a perfect answer! (Though I supposed that the solution would be easier — I wasted a lot of time trying to find it after being stuck in my current program). After reading your answer several times and then testing the code snippets with different changes, I at last understand much better, how lookahead and lookbehind work. As for the last solution, my question remains: how to interpolate `@vowels` or `$vowels` into `$vowel-regex`. In my programs, it would be better not to have such info 'hard-coded'. – Eugene Barsky Nov 04 '17 at 19:28
  • 1
    Finally, I've got it! `my $vowel-regex = "/<-[$vowels]>/".EVAL;` Thanks again for your explanations! – Eugene Barsky Nov 04 '17 at 21:32
  • @EugeneBarsky You can do the eval in-line: `my $match-consonant-rx = /<{ "<-[$vowels]>" }>/;` – Jim Balter Aug 25 '19 at 18:52