From 4965ece6acebea84f7d9db224c8110a157462a8d Mon Sep 17 00:00:00 2001 From: Packy Anderson Date: Tue, 11 Nov 2025 22:00:40 -0500 Subject: Challenge 347 solutions by Packy Anderson * Raku that is finally Raku-ish * Perl * Python that kinda looks like Raku * Elixir that is starting to look like Elixir 1 blog post --- challenge-347/packy-anderson/README.md | 2 +- challenge-347/packy-anderson/blog.txt | 1 + challenge-347/packy-anderson/elixir/ch-1.exs | 77 ++++++++++++++++++++++++---- challenge-347/packy-anderson/elixir/ch-2.exs | 41 +++++++++++---- challenge-347/packy-anderson/perl/ch-1.pl | 73 +++++++++++++++++++++++--- challenge-347/packy-anderson/perl/ch-2.pl | 37 ++++++++++--- challenge-347/packy-anderson/python/ch-1.py | 75 ++++++++++++++++++++++----- challenge-347/packy-anderson/python/ch-2.py | 41 +++++++++------ challenge-347/packy-anderson/raku/ch-1.raku | 66 +++++++++++++++++++++--- challenge-347/packy-anderson/raku/ch-2.raku | 36 ++++++++++--- 10 files changed, 367 insertions(+), 82 deletions(-) diff --git a/challenge-347/packy-anderson/README.md b/challenge-347/packy-anderson/README.md index 4b575063b3..b54c5bd3b8 100644 --- a/challenge-347/packy-anderson/README.md +++ b/challenge-347/packy-anderson/README.md @@ -23,4 +23,4 @@ ## Blog Post -[Perl Weekly Challenge: Whoa-oh-oh! Sing about parens!](https://packy.dardan.com/b/dX) +[Perl Weekly Challenge: Oh, oh, formatted strings, give me some thing...](https://packy.dardan.com/b/dp) diff --git a/challenge-347/packy-anderson/blog.txt b/challenge-347/packy-anderson/blog.txt index e69de29bb2..f7505b9a52 100644 --- a/challenge-347/packy-anderson/blog.txt +++ b/challenge-347/packy-anderson/blog.txt @@ -0,0 +1 @@ +https://packy.dardan.com/b/dp \ No newline at end of file diff --git a/challenge-347/packy-anderson/elixir/ch-1.exs b/challenge-347/packy-anderson/elixir/ch-1.exs index 45a0ed2251..5e9fe3b639 100755 --- a/challenge-347/packy-anderson/elixir/ch-1.exs +++ b/challenge-347/packy-anderson/elixir/ch-1.exs @@ -1,26 +1,83 @@ #!/usr/bin/env elixir defmodule PWC do + def format_date(_, _, _, year) when year < 1900, + do: "Year must be between 1900-2100" - def solution(ints) do - IO.puts("Input: @ints = (" <> Enum.join(ints, ", ") <> ")") - {sign, explain} = PWC.productSign(ints) - IO.puts("Output: " <> to_string(sign) ) - IO.puts("\n" <> explain) + def format_date(_, _, _, year) when year > 2100, + do: "Year must be between 1900-2100" + + def format_date(_, month, mnum, _) when is_nil(mnum), + do: "Unknown month '#{month}'" + + def format_date(dnum, _, mnum, year) do + with {:ok, date} <- Date.new(year, mnum, dnum) do + "\"#{date |> Date.to_iso8601}\"" + else + {:error, :invalid_date} -> "Invalid date" + end + end + + def format_date(str) do + [day, month, year] = String.split(str) + + m = Regex.named_captures(~r'(?\d+)(?\D+)', day) + dnum = m["dnum"] |> String.to_integer # make sure it's an int + + if not ( + ((dnum == 1 or dnum == 21 or dnum == 31) and + m["dord"] == "st") + or + ((dnum == 2 or dnum == 22) and m["dord"] == "nd") + or + ((dnum == 3 or dnum == 23) and m["dord"] == "rd") + or + m["dord"] == "th" + ) do + "#{day} has the incorrect ordinal" + else + year = year |> String.to_integer # make sure it's an int + mnum = Map.get(%{ + "Jan" => 1, "Feb" => 2, "Mar" => 3, "Apr" => 4, + "May" => 5, "Jun" => 6, "Jul" => 7, "Aug" => 8, + "Sep" => 9, "Oct" => 10, "Nov" => 11, "Dec" => 12 + }, month) + format_date(dnum, month, mnum, year) + end + end + + def solution(str) do + IO.puts("Input: $str = \"#{str}\"") + IO.puts("Output: " <> format_date(str)) end end IO.puts("Example 1:") -PWC.solution() +PWC.solution("1st Jan 2025") IO.puts("\nExample 2:") -PWC.solution() +PWC.solution("22nd Feb 2025") IO.puts("\nExample 3:") -PWC.solution() +PWC.solution("15th Apr 2025") IO.puts("\nExample 4:") -PWC.solution() +PWC.solution("23rd Oct 2025") IO.puts("\nExample 5:") -PWC.solution() +PWC.solution("31st Dec 2025") + +IO.puts("\nExample Year Too Big:") +PWC.solution("31st Dec 2525") + +IO.puts("\nExample Year Too Small:") +PWC.solution("31st Dec 1825") + +IO.puts("\nExample Bad Ordinal:") +PWC.solution("31nd Dec 2025") + +IO.puts("\nExample Bad Month:") +PWC.solution("30th Avril 2025") + +IO.puts("\nExample Bad Date:") +PWC.solution("31st Feb 2025") diff --git a/challenge-347/packy-anderson/elixir/ch-2.exs b/challenge-347/packy-anderson/elixir/ch-2.exs index 45a0ed2251..6bd182cf1f 100755 --- a/challenge-347/packy-anderson/elixir/ch-2.exs +++ b/challenge-347/packy-anderson/elixir/ch-2.exs @@ -1,26 +1,47 @@ #!/usr/bin/env elixir defmodule PWC do + def format_phone(list, formatted) when length(list) < 4 do + formatted <> Enum.join(list) + end + + def format_phone(list, formatted) when length(list) == 4 do + {a, list} = {hd(list), tl(list)} + {b, list} = {hd(list), tl(list)} + formatted <> "#{a}#{b}-" <> Enum.join(list) + end + + def format_phone(list, formatted) when length(list) > 4 do + {a, list} = {hd(list), tl(list)} + {b, list} = {hd(list), tl(list)} + {c, list} = {hd(list), tl(list)} + format_phone(list, formatted <> "#{a}#{b}#{c}-") + end + + def format_phone(phone) do + phone + |> String.replace(~r/\D/, "") + |> String.graphemes + |> format_phone("") + end - def solution(ints) do - IO.puts("Input: @ints = (" <> Enum.join(ints, ", ") <> ")") - {sign, explain} = PWC.productSign(ints) - IO.puts("Output: " <> to_string(sign) ) - IO.puts("\n" <> explain) + def solution(phone) do + IO.puts("Input: $phone = \"#{phone}\"") + IO.puts("Output: \"#{format_phone(phone)}\"") end end IO.puts("Example 1:") -PWC.solution() +PWC.solution("1-23-45-6") IO.puts("\nExample 2:") -PWC.solution() +PWC.solution("1234") IO.puts("\nExample 3:") -PWC.solution() +PWC.solution("12 345-6789") IO.puts("\nExample 4:") -PWC.solution() +PWC.solution("123 4567") IO.puts("\nExample 5:") -PWC.solution() +PWC.solution("123 456-78") diff --git a/challenge-347/packy-anderson/perl/ch-1.pl b/challenge-347/packy-anderson/perl/ch-1.pl index 98a155f02b..eb813f7671 100755 --- a/challenge-347/packy-anderson/perl/ch-1.pl +++ b/challenge-347/packy-anderson/perl/ch-1.pl @@ -1,22 +1,79 @@ #!/usr/bin/env perl use v5.40; -sub solution(@arr) { - say 'Input: @arr = (' . join(', ', @arr) . ')'; - say 'Output: (' . join(', ', @arr) . ')'; +use Time::Local; +use Time::Piece; + +my %months = ( + Jan => 1, Feb => 2, Mar => 3, Apr => 4, May => 5, Jun => 6, + Jul => 7, Aug => 8, Sep => 9, Oct => 10, Nov => 11, Dec => 12 +); + +sub formatDate($str) { + my ($day, $month, $year) = split / /, $str; + + my ($dnum, $dord) = $day =~ /(\d+)(\D+)/; + return "$day has the incorrect ordinal" + unless + (($dnum == 1 || $dnum == 21 || $dnum == 31) && $dord eq "st") + || + (($dnum == 2 || $dnum == 22) && $dord eq "nd") + || + (($dnum == 3 || $dnum == 23) && $dord eq "rd") + || + $dord eq "th"; + $day = $dnum; # grab just the numeric portion + + return "Unknown month '$month'" + unless exists $months{$month}; + $month = $months{$month}; # convert to numeric + + return "Year must be between 1900-2100" + unless 1900 <= $year && $year <= 2100; + + my $date; + eval { + my $epoch = timelocal(0, 0, 0, $day, $month-1, $year); + $date = Time::Piece->new($epoch); + }; + if (my $err = $@) { # get rid of line info in the error + $err =~ s{at .+ line \d+.\n}{}; + return $err; + } + return qq/"@{[ $date->date ]}"/; +} + +sub solution($str) { + say qq/Input: \$str = "$str"/; + say qq/Output: / . formatDate($str); } say "Example 1:"; -solution(); +solution("1st Jan 2025"); say "\nExample 2:"; -solution(); +solution("22nd Feb 2025"); say "\nExample 3:"; -solution(); +solution("15th Apr 2025"); say "\nExample 4:"; -solution(); +solution("23rd Oct 2025"); say "\nExample 5:"; -solution(); +solution("31st Dec 2025"); + +say "\nExample Year Too Big:"; +solution("31st Dec 2525"); + +say "\nExample Year Too Small:"; +solution("31st Dec 1825"); + +say "\nExample Bad Ordinal:"; +solution("31nd Dec 2025"); + +say "\nExample Bad Month:"; +solution("30th Avril 2025"); + +say "\nExample Bad Date:"; +solution("31st Feb 2025"); diff --git a/challenge-347/packy-anderson/perl/ch-2.pl b/challenge-347/packy-anderson/perl/ch-2.pl index 98a155f02b..4226e87493 100755 --- a/challenge-347/packy-anderson/perl/ch-2.pl +++ b/challenge-347/packy-anderson/perl/ch-2.pl @@ -1,22 +1,43 @@ #!/usr/bin/env perl use v5.40; -sub solution(@arr) { - say 'Input: @arr = (' . join(', ', @arr) . ')'; - say 'Output: (' . join(', ', @arr) . ')'; +sub formatPhone2($phone, $formatted) { + if (length($phone) < 4) { + $formatted . $phone; + } + elsif (length($phone) == 4) { + $formatted . substr($phone, 0,2) . "-" . substr($phone, 2,2); + } + else { + formatPhone2( + substr($phone, 3), + $formatted . substr($phone, 0, 3) . "-" + ); + } +} + +sub formatPhone($phone) { + $phone =~ s/\D+//g; + formatPhone2($phone, ""); +} + +sub solution($phone) { + say qq/Input: \$phone = "$phone"/; + say qq/Output: "@{[formatPhone($phone)]}"/; } say "Example 1:"; -solution(); +solution("1-23-45-6"); say "\nExample 2:"; -solution(); +solution("1234"); say "\nExample 3:"; -solution(); +solution("12 345-6789"); say "\nExample 4:"; -solution(); +solution("123 4567"); say "\nExample 5:"; -solution(); +solution("123 456-78"); + diff --git a/challenge-347/packy-anderson/python/ch-1.py b/challenge-347/packy-anderson/python/ch-1.py index d669a661ec..4e6c939861 100755 --- a/challenge-347/packy-anderson/python/ch-1.py +++ b/challenge-347/packy-anderson/python/ch-1.py @@ -1,28 +1,77 @@ #!/usr/bin/env python -def distinctAverages(nums): - pass +from datetime import date +import re -def int_join(joiner, arr): - return joiner.join(map(str, arr)) +months = { + 'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6, + 'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12 +} -def solution(nums): - print(f'Input: @nums = ({int_join(", ", nums)})') - count, explain = distinctAverages(nums) - print(f'Output: {count}\n\n{explain}') +def format_date(dstr): + day, month, year = dstr.split() + m = re.match(r'(\d+)(\D+)', day) + dnum = int(m.group(1)) # make sure it's an int + dord = m.group(2) + if not ( + ((dnum == 1 or dnum == 21 or dnum == 31) and dord == "st") + or + ((dnum == 2 or dnum == 22) and dord == "nd") + or + ((dnum == 3 or dnum == 23) and dord == "rd") + or + dord == "th" + ): + return f"{day} has the incorrect ordinal" + day = dnum # grab just the numeric portion + + if not month in months: + return f"Unknown month '{month}'" + + month = months[month] # convert to numeric + + year = int(year) # make sure it's an int + if not (1900 <= year <= 2100): + return "Year must be between 1900-2100" + + try: + dateobj = date(year, month, day) + except ValueError as err: + return err + + return f'"#{dateobj.strftime("%Y-%m-%d")}"' + +def solution(dstr): + print(f'Input: $str = "{dstr}"') + print(f'Output: {format_date(dstr)}') print('Example 1:') -solution() +solution("1st Jan 2025") print('\nExample 2:') -solution() +solution("22nd Feb 2025") print('\nExample 3:') -solution() +solution("15th Apr 2025") print('\nExample 4:') -solution() +solution("23rd Oct 2025") print('\nExample 5:') -solution() +solution("31st Dec 2025") + +print('\nExample Year Too Big:') +solution("31st Dec 2525") + +print('\nExample Year Too Small:') +solution("31st Dec 1825") + +print('\nExample Bad Ordinal:') +solution("31nd Dec 2025") + +print('\nExample Bad Month:') +solution("30th Avril 2025") + +print('\nExample Bad Date:') +solution("31st Feb 2025") diff --git a/challenge-347/packy-anderson/python/ch-2.py b/challenge-347/packy-anderson/python/ch-2.py index d669a661ec..b835c0f190 100755 --- a/challenge-347/packy-anderson/python/ch-2.py +++ b/challenge-347/packy-anderson/python/ch-2.py @@ -1,28 +1,37 @@ #!/usr/bin/env python -def distinctAverages(nums): - pass - -def int_join(joiner, arr): - return joiner.join(map(str, arr)) - -def solution(nums): - print(f'Input: @nums = ({int_join(", ", nums)})') - count, explain = distinctAverages(nums) - print(f'Output: {count}\n\n{explain}') - +import re + +def format_phone2(phone, formatted): + if len(phone) < 4: + return formatted + phone + elif len(phone) == 4: + return formatted + phone[0:2] + "-" + phone[2:4] + else: + return format_phone2( + phone[3:], + formatted + phone[0:3] + "-" + ) + +def format_phone(phone): + phone = re.sub(r'\D', '', phone) + return format_phone2(phone, "") + +def solution(phone): + print(f'Input: $phone = "{phone}"') + print(f'Output: "{format_phone(phone)}"') print('Example 1:') -solution() +solution("1-23-45-6") print('\nExample 2:') -solution() +solution("1234") print('\nExample 3:') -solution() +solution("12 345-6789") print('\nExample 4:') -solution() +solution("123 4567") print('\nExample 5:') -solution() +solution("123 456-78") diff --git a/challenge-347/packy-anderson/raku/ch-1.raku b/challenge-347/packy-anderson/raku/ch-1.raku index 53bd47e1a7..76de0214fb 100755 --- a/challenge-347/packy-anderson/raku/ch-1.raku +++ b/challenge-347/packy-anderson/raku/ch-1.raku @@ -1,22 +1,72 @@ #!/usr/bin/env raku use v6; -sub solution(@arr) { - say 'Input: @arr = (' ~ @arr.join(', ') ~ ')'; - say 'Output: (' ~ @arr.join(', ') ~ ')'; +my %months = ( + Jan => 1, Feb => 2, Mar => 3, Apr => 4, May => 5, Jun => 6, + Jul => 7, Aug => 8, Sep => 9, Oct => 10, Nov => 11, Dec => 12 +); + +sub formatDate($str) { + my ($day, $month, $year) = $str.split(" "); + + my $m = $day ~~ /(\d+)(\D+)/; + return "$day has the incorrect ordinal" + unless + (($m[0] == 1 || $m[0] == 21 || $m[0] == 31) && $m[1] eq "st") + || + (($m[0] == 2 || $m[0] == 22) && $m[1] eq "nd") + || + (($m[0] == 3 || $m[0] == 23) && $m[1] eq "rd") + || + $m[1] eq "th"; + $day = $m[0]; # grab just the numeric portion + + return "Unknown month '$month'" + unless %months{$month}:exists; + $month = %months{$month}; # convert to numeric + + return "Year must be between 1900-2100" + unless 1900 <= $year <= 2100; + + my $date; + try { + $date = Date.new($year, $month, $day); + } + return $! if $!; + return qq/"$date"/; +} + +sub solution($str) { + say qq/Input: \$str = "$str"/; + say qq/Output: / ~ formatDate($str); } say "Example 1:"; -solution(); +solution("1st Jan 2025"); say "\nExample 2:"; -solution(); +solution("22nd Feb 2025"); say "\nExample 3:"; -solution(); +solution("15th Apr 2025"); say "\nExample 4:"; -solution(); +solution("23rd Oct 2025"); say "\nExample 5:"; -solution(); +solution("31st Dec 2025"); + +say "\nExample Year Too Big:"; +solution("31st Dec 2525"); + +say "\nExample Year Too Small:"; +solution("31st Dec 1825"); + +say "\nExample Bad Ordinal:"; +solution("31nd Dec 2025"); + +say "\nExample Bad Month:"; +solution("30th Avril 2025"); + +say "\nExample Bad Date:"; +solution("31st Feb 2025"); diff --git a/challenge-347/packy-anderson/raku/ch-2.raku b/challenge-347/packy-anderson/raku/ch-2.raku index 53bd47e1a7..581d2f97e2 100755 --- a/challenge-347/packy-anderson/raku/ch-2.raku +++ b/challenge-347/packy-anderson/raku/ch-2.raku @@ -1,22 +1,42 @@ #!/usr/bin/env raku use v6; -sub solution(@arr) { - say 'Input: @arr = (' ~ @arr.join(', ') ~ ')'; - say 'Output: (' ~ @arr.join(', ') ~ ')'; +multi formatPhone($phone where $phone.chars < 4, $formatted) { + $formatted ~ $phone; +} + +multi formatPhone($phone where $phone.chars == 4, $formatted) { + $formatted ~ $phone.substr(0..1) ~ "-" ~ $phone.substr(2..3); +} + +multi formatPhone($phone, $formatted) { + formatPhone( + $phone.substr(3), + $formatted ~ $phone.substr(0..2) ~ "-" + ); +} + +multi formatPhone(Str $phone is copy) { + $phone ~~ s:global/\D+//; + formatPhone($phone, ""); +} + +sub solution($phone) { + say qq/Input: \$phone = "$phone"/; + say qq/Output: "{formatPhone($phone)}"/; } say "Example 1:"; -solution(); +solution("1-23-45-6"); say "\nExample 2:"; -solution(); +solution("1234"); say "\nExample 3:"; -solution(); +solution("12 345-6789"); say "\nExample 4:"; -solution(); +solution("123 4567"); say "\nExample 5:"; -solution(); +solution("123 456-78"); -- cgit