01 August 2025 | Challenge 332 |
Binary Regularities
Task 1: Binary Date
Submitted by: Mohammad Sajid Anwar
You are given a date in the format YYYY-MM-DD
.
Write a script to convert it into binary date.
Example 1
Input: $date = "2025-07-26"
Output: "11111101001-111-11010"
Example 2
Input: $date = "2000-02-02"
Output: "11111010000-10-10"
Example 3
Input: $date = "2024-12-31"
Output: "11111101000-1100-11111"
Solution
It would be easy to split the input string at hyphens and print the resulting parts as binary numbers.
As the given input shall represent a date, there shall be at least a check for validity.
Using Date::Manip::Date::parse_date
to parse input data has the side effect of permitting a lot of
input formats beyond "2025-07-29"
,
including "Jul 29 2025"
or even "Last Tuesday in July 2025"
.
use strict;
use warnings;
use Date::Manip::Date;
sub binary_date {
my $date = Date::Manip::Date->new;
$date->parse_date(shift) && die $date->err;
sprintf "%b-%b-%b", $date->printf(qw(%Y %f %e));
}
See the full solution to task 1.
Task 2: Odd Letters
Submitted by: Mohammad Sajid Anwar
You are given a string.
Write a script to find out if each letter in the given string appeared odd number of times.
Example 1
Input: $str = "weekly"
Output: false
w: 1 time
e: 2 times
k: 1 time
l: 1 time
y: 1 time
The letter 'e' appeared 2 times i.e. even.
Example 2
Input: $str = "perl"
Output: true
Example 3
Input: $source = "challenge"
Output: false
Solution
It is possible to match a string containing a character that appears an even number of times with a single regex. If that regex does not match, all characters are odd.
In pseudo-code it could look like:
/
(.) # match a single character
(?<!\1.+) # that is not preceded by itself
([^\1]*\1) # and followed by any number of other characters and itself
(?:(?-1){2})* # and followed by an even number of the previous sub-expression
(?!.*\1) # and not followed by itself
/x
However, there are two issues:
(?<!\1.+)
is a negative, unlimited variable length look-behind assertion, which is not supported.[^\1]
does not expand\1
to the content of the capture group #1 and$1
doesn’t provide access to it in this context neither.
We need to work around these:
- a true variable length look-behind can be emulated utilizing Grimy’s trick.
- a bracketed character class containing a backreference can be build inside a postponed sub-expression
Putting these together results in:
use strict;
use warnings;
sub odd_letters {
shift !~ /
(.)
(?!(?=(.*))(\1.+(?=\g{-2}$)|(?<=(?=x^|(?-1)).))) # Grimy's trick
((??{qr([^$1]*)})\1) # postponed sub-expression
(?:(?-1){2})*
(?!.*\1)
/x;
}
See the full solution to task 2.
If you have a question about this post or if you like to comment on it, feel free to open an issue in my github repository.