5

My RAKU Code:

sub comments {
    if ($DEBUG) { say "<filtering comments>\n"; }
    my @filteredtitles = ();

    # This loops through each track
    for @tracks -> $title {

        ##########################
        # LAB 1 TASK 2           #
        ##########################
        ## Add regex substitutions to remove superflous comments and all that follows them
        ## Assign to $_ with smartmatcher (~~)
        ##########################
        $_ = $title;

        if ($_) ~~ s:g:mrx/ .*<?[\(^.*]> / {

        # Repeat for the other symbols

        ########################## End Task 2

        # Add the edited $title to the new array of titles
            @filteredtitles.push: $_;
        }
    }
        # Updates @tracks
        return @filteredtitles;
}

Result when compiling: Error Compiling! Placeholder variable '@_' may not be used here because the surrounding block doesn't take a signature.

Is there something obvious that I am missing? Any help is appreciated.

Elizabeth Mattijsen
  • 25,654
  • 3
  • 75
  • 105
Homerian
  • 183
  • 4
  • Could you explain your regex adverbs on the right side of the `~~` smartmatch operator? I see `:r` might stand for ratcheting, but I don't think Raku has a `:x` equivalent of Perl5's `/x`, since the 'disregard whitespace' switch is now Raku's default. Maybe something like `m:r:g` ? – jubilatious1 Apr 14 '22 at 18:41

2 Answers2

3

Here's what I ended up with:

my @tracks = <Foo Ba(r B^az>;

sub comments {

    my @filteredtitles;

    for @tracks -> $_ is copy {

        s:g / <[\(^]> //;

        @filteredtitles.push: $_;
    }

    return @filteredtitles;
}

The is copy ensures the variable set up by the for loop is mutable.

The s:g/...//; is all that's needed to strip the unwanted characters.


One thing no one can help you with is the error you reported. I currently think you just got confused.

Here's an example of code that generates that error:

do { @_ }

But there is no way the code you've shared could generate that error because it requires that there is an @_ variable in your code, and there isn't one.


One way I can help in relation to future problems you may report on StackOverflow is to encourage you to read and apply the guidance in Minimal Reproducible Example.


While your code did not generate the error you reported, it will perhaps help you if you know about some of the other compile time and run time errors there were in the code you shared.

Compile-time errors:

  • You wrote s:g:mrx. That's invalid: Adverb mrx not allowed on substitution.

  • You missed out the third slash of the s///. That causes mayhem (see below).

There were several run-time errors, once I got past the compile-time errors. I'll discuss just one, the regex:

  • .*<?[...]> will match any sub-string with a final character that's one of the ones listed in the [...], and will then capture that sub-string except without the final character. In the context of an s:g/...// substitution this will strip ordinary characters (captured by the .*) but leave the special characters.

    This makes no sense.

    So I dropped the .*, and also the ? from the special character pattern, changing it from <?[...]> (which just tries to match against the character, but does not capture it if it succeeds) to just <[...]> (which also tries to match against the character, but, if it succeeds, does capture it as well).


A final comment is about an error you made that may well have seriously confused you.

In a nutshell, the s/// construct must have three slashes.

In your question you had code of the form s/.../ (or s:g/.../ etc), without the final slash. If you try to compile such code the parser gets utterly confused because it will think you're just writing a long replacement string.

For example, if you wrote this code:

if s/foo/ { say 'foo' }
if m/bar/ { say 'bar' }

it'd be as if you'd written:

if s/foo/ { say 'foo' }\nif m/...

which in turn would mean you'd get the compile-time error:

Missing block
------> if m/⏏bar/ { ... }
    expecting any of:
        block or pointy block
        ...

because Raku(do) would have interpreted the part between the second and third /s as the replacement double quoted string of what it interpreted as an s/.../.../ construct, leading it to barf when it encountered bar.

So, to recap, the s/// construct requires three slashes, not two.

(I'm ignoring syntactic variants of the construct such as, say, s [...] = '...'.)

raiph
  • 31,607
  • 3
  • 62
  • 111
  • 1
    just `@tracks.map: { S:g / <[\(^]> // }` seems to do the trick ;-) – Massa Apr 16 '22 at 01:58
  • 1
    @Massa Nice one liner. :) Would you be willing to write that up as an answer? Just the `my @tracks` line plus your one liner? Maybe with some brief explanation / links to the doc? I think it would make a nice contrast with my long answer, and would get most of the upvotes, and would hopefully get accepted if @Homerian ever returns to SO, and that those would all be good things. :) – raiph Apr 16 '22 at 09:31
  • 1
    Will do, in a couple of minutes! – Massa Apr 17 '22 at 18:09
3

So, in contrast with @raiph's answer, here's what I have:

my @tracks = <Foo Ba(r B^az>.map: { S:g / <[\(^]> // };

Just that. Nothing else. Let's dissect it, from the inside out:

This part: / <[\(^]> / is a regular expression that will match one character, as long as it is an open parenthesis (represented by the \() or a caret (^). When they go inside the angle brackets/square brackets combo, it means that is an Enumerated character class.

Then, the: S introduces the non-destructive substitution, i.e., a quoting construct that will make regex-based substitutions over the topic variable $_ but will not modify it, just return its value with the modifications requested. In the code above, S:g brings the adverb :g or :global (see the global adverb in the adverbs section of the documentation) to play, meaning (in the case of the substitution) "please make as many as possible of this substitution" and the final / marks the end of the substitution text, and as it is adjacent to the second /, that means that

S:g / <[\(^]> //

means "please return the contents of $_, but modified in such a way that all its characters matching the regex <[\(^]> are deleted (substituted for the empty string)"

At this point, I should emphasize that regular expressions in Raku are really powerful, and that reading the entire page (and probably the best practices and gotchas page too) is a good idea.

Next, the: .map method, documented here, will be applied to any Iterable (List, Array and all their alikes) and will return a sequence based on each element of the Iterable, altered by a Code passed to it. So, something like:

@x.map({ S:g / foo /bar/ })

essencially means "please return a Sequence of every item on @x, modified by substituting any appearance of the substring foo for bar" (nothing will be altered on @x). A nice place to start to learn about sequences and iterables would be here.

Finally, my one-liner

my @tracks = <Foo Ba(r B^az>.map: { S:g / <[\(^]> // };

can be translated as:

I have a List with three string elements

Foo
Ba(r
B^az

(This would be a placeholder for your "list of titles"). Take that list and generate a second one, that contains every element on it, but with all instances of the chars "open parenthesis" and "caret" removed.

Ah, and store the result in the variable @tracks (that has my scope)

Massa
  • 8,647
  • 2
  • 25
  • 26