PWC148 - Eban Numbers


Here we are with TASK #1 from The Weekly Challenge #148. Enjoy!

The challenge

Write a script to generate all Eban Numbers <= 100.

An Eban number is a number that has no letter ‘e’ in it when the number is spelled in English (American or British).


2, 4, 6, 30, 32 are the first 5 Eban numbers.

The questions

I think that number means positive or non-negative integer, right? (Either way, zEro would be out).

The solution

This week I felt lazy and decided that giants are my friends. So I took a look at CPAN and presto!, there I found Lingua::EN::Numbers.

Well… right, it’s customary for me to start with Raku for the first challenge, but presto!, there was an equally named module for Raku too: Lingua::EN::Numbers.

So the algorithm is pretty basic: convert the numbers in their English wording, then ban the es:

#!/usr/bin/env raku
use v6;
use Lingua::EN::Numbers;
sub MAIN (Int:D $max = 100) { ebans-upto($max)».put }
sub ebans-upto (Int:D $max) { (^$max).grep({cardinal($_) !~~ /:i e/}) }

The case-insensitive match is probably overkill but it’s part of being defensive. Who knows when and where I’m going to reuse this code?!?

OK, Perl now:

#!/usr/bin/env perl
use v5.24;
use warnings;
use experimental 'signatures';
no warnings 'experimental::signatures';
use FindBin '$Bin';
use lib "$Bin/local/lib/perl5";
use Lingua::EN::Numbers 'num2en';
map { say } ebans_upto(shift // 100);
sub ebans_upto ($max) { grep {num2en($_) !~ /e/i } 1 .. $max };

Nothing new or different.

Had I to do this differently, I’d probably observe that:

  • everything matching / [1789] /mxs is out (one for various reasons)
  • everything matching / 2\d \z/mxs is out too
  • everything matching / [35] \z/mxs or / [35]\d\d \z/mxs is out
  • everything else should be in.

So the solution might even have been this, hopefully valid for any input (not only 100) until proven otherwise:

#!/usr/bin/env perl
use v5.24;
use warnings;
use experimental 'signatures';
no warnings 'experimental::signatures';
sub is_eban ($n) { $n !~ m{ [1789] | (?:2\d\z) | (?:[35](?:\d\d)?\z) }mxs }
is_eban($_) && say for 1 .. shift // 100;

But I’m a lazy folk so I’ll stick to the modules-based solution.

Stay safe and see you soon!

Comments? Octodon, Twitter, GitHub, Reddit, or drop me a line!