I’ve been doing the Perl Weekly
Challenges. The
latest
involved transpositions. (Note that this
is open until 2 May 2021.)
TASK #1 › Valid Phone Numbers
You are given a text file.
Write a script to display all valid phone numbers in the given text file.
Both of this week's challenges took the form of file input and output.
This one was basically a regexp, derivable from the sample data, and
is trivially done in shell:
egrep "^ *(\+[0-9]{2}|\([0-9]{2}\)|[0-9]{4}) [0-9]{10} *$"
Perl isn't much longer:
while (<>) {
print if /^\s*(\+[0-9]{2}|\([0-9]{2}\)|[0-9]{4}) [0-9]{10}\s*$/;
}
Raku has its own special way of doing regexps:
for lines() {
say $_ if /^\s*(\+<[0..9]> ** 2|\(<[0..9]> ** 2\)|<[0..9]> ** 4)\s<[0..9]> ** 10\s*$/;
}
and Python, Ruby and Rust all looked like variants of the Perl, with
more or less clutter about reading standard input and writing to
standard output. (I wrote a test harness too, which would feed the
input file to the program of choice, then compare the output with the
template. Which, as it turned out, was the same basic transposition
code I'd need for part 2.)
TASK #2 › Transpose File
You are given a text file.
Write a script to transpose the contents of the given file.
(Where the input file is a simple CSV.)
This is really three separate tasks: read the input CSV, do the
transposition, and write the output. If I were doing it in the real
world, this would probably be three separate library functions,
perhaps with a wrapper if the three-in-one task were done commonly.
For Perl of course I used the
Text::CSV_XS
module. (With some sugar to let the thing take either a
command line parameter or stdin; for the others I didn't bother.)
my $csv = Text::CSV_XS->new({eol => $/});
my $fh;
if (defined $ARGV[0] && -e $ARGV[0]) {
open $fh,'<',$ARGV[0];
} else {
$fh=*STDIN;
}
I can use autovivification to assign to arbitrary elements in
arbitrary lists.
my @a;
my $ri=0;
while (my $row=$csv->getline($fh)) {
foreach my $ci (0..$#{$row}) {
$a[$ci][$ri]=$row->[$ci];
}
$ri++;
}
close $fh;
$csv->say(*STDOUT,$_) for @a;
The other languages don't have CSV handling built in and I try not to
use external modules; for this situation, a simple split on commas was
adequate. Raku:
my @a;
my $ri=0;
for lines() {
my @r=split ',',$_;
for 0..@r.elems-1 -> $ci {
@a[$ci][$ri]=@r[$ci];
}
$ri++;
}
for @a -> @r {
say join(',',@r);
}
Now we lose autovivification and have to have a bit more guard code.
Python:
a=[]
for line in fileinput.input():
line=line.rstrip()
r=line.split(',')
for ci in range(len(r)):
while len(a) < ci+1:
a.append([])
a[ci].append(r[ci])
for r in a:
print (','.join(r))
and Ruby and Rust work more or less the same way.
Full code on
github.
Comments on this post are now closed. If you have particular grounds for adding a late comment, comment on a more recent post quoting the URL of this one.