Perl Weekly Challenge 131: Find Pairs

by Abigail

Challenge

You are given a string of delimiter pairs and a string to search.

Write a script to return two strings, the first with any characters matching the “opening character” set, the second with any matching the “closing character” set.

Example 1

Input:
    Delimiter pairs: ""[]()
    Search String: "I like (parens) and the Apple ][+" they said.

Output:
    "(["
    ")]"

Example 2

Input:
    Delimiter pairs: **//<>
    Search String: /* This is a comment (in some languages) */ <could be a tag>

Output:
    /**/<
    /**/>

Discussion

What a strange way to phrase the exercise. The entire "delimiter pairs" is a red herring. We are not asked to do anything with delimiting pairs. This is clear from both examples. Take for instance the first example; the first delimiting pair using " for both the opening delimiter and the closing delimiter. And the string to search in, uses a single pair of double quotes as delimiting pair. Yet, the pair appears in both the output strings.

So, basically we are given a string, and two sets of characters we need to extract from the string, and for some perverse reason, the two sets of characters are interleaved. Weird.

Perl

First, we read the input. First line of input are the interleaved sets of characters to extract - second line of input is the string we want to search:

chomp (my $chars = <>);
$_ = <>;

We remove the newline from the first line we read; there is no need to bother to remove it from the second line.

We now extract the characters from $char in the odd and even positions, giving us two sets of characters. We do this by removing the characters on the even and odd positions from $char; and since we use the /r modifier, $char itself is unmodified, and the modified string is returned. We also escape any slashes in the sets (for reasons which will soon be clear).

my $odds = $chars =~ s/(.)./$1/gr =~ s!([/\\])!\\$1!r;
my $even = $chars =~ s/.(.)/$1/gr =~ s!([/\\])!\\$1!r;

We can now use y///dc to remove any characters which aren't in the sets we need to extract — this leaves use with the characters we need to extract. Since y/// doesn't do interpolation, we use eval. And this explains why we need to escape any slashes above.

say eval "y/$odds//dcr";
say eval "y/$even//dcr";

Find the full program on GitHub.


Please leave any comments as a GitHub issue.