TASK #1: Defang IP Address
You are given a valid IPv4 address.
Write a script to return the defanged version of the given IP address.
A defanged IP address replaces every period '.' with '[.]'.
#!/usr/bin/perl use strict; use warnings; =begin Here my solution TASK #1 along with alternatives from Niels van Dijke and James Curtis-Smith. I did some benchmark (https://metacpan.org/pod/Benchmark) with 'timethese': James' join+split is the fastest solution, even when the validation in Niels' and my solution is removed =cut use Data::Validate::IP qw(is_ipv4); sub defangIP { if (is_ipv4($_[0])) { $_[0] =~ s/\./[.]/g; } else { print("No valid IP address!"); }# Inspired by Niels van Dijke's oneliner which uses the necessary /r switch # (Niels uses for validation another module Net::IP) # (is_ipv4($_[0])) ? $_[0] =~ s/\./[.]/gr : "No valid IP address!"; # James Curtis-Smith solution: # join '[.]', split /\./, $_[0]; } # TESTS my $ip; # Example 1 $ip = "1.1.1.1"; print(defangIP($ip), "\n");# Output: 1[.]1[.]1[.]1 # Example 2 $ip = "255.101.1.0"; print(defangIP($ip), "\n");# Output: 255[.]101[.]1[.]0 # Example 3 $ip = "123.234.345.001"; print(defangIP($ip), "\n");# Output: "No valid IP address! # Example 4# From: https://metacpan.org/pod/Data::Validate::IP # There are security implications to this around certain oddly formed addresses. # Notably, an address like "010.0.0.1" is technically valid, but the operating # system will treat '010' as an octal number: '010.0.0.1' is interpreted as '8.0.0.1' # James' solution and Niels' original do not take that into account. $ip = "010.0.0.1"; print(defangIP($ip), "\n");# Output: "No valid IP address!
To better understand James Curtis-Smith's solution, study the following code which also clarifies the role of James' implicit $_ (yes, I love using parentheses to make 'thoughts' clear ... my LISP background ...):#!/usr/bin/perl use strict; use warnings; use Benchmark qw(:all); =begin Here is my solution for TASK #2, along with alternatives from Niels van Dijke and James Curtis-Smith. I shared the benchmark results, which show some variability when run multiple times. Nonetheless, James's solution is the fastest. =cut# Reinier Maliepaard: function to calculate total sum using split and for sub ascii_differences_sum_split_1 { my @chars = split(//, $_[0]); my $total_sum = 0; for my $i (0 .. $#chars - 1) { $total_sum += abs(ord($chars[$i]) - ord($chars[$i + 1])); } return($total_sum); }# James Curtis-Smith: function to calculate total sum using split and for sub ascii_differences_sum_split_2 { my ($t, @l) = (0, split //, $_[0]); my $f = ord shift @l; ($t += abs($f - ord)), $f=ord for @l; $t; }# Niels van Dijke: function to calculate total sum using sum0 and slide use List::Util qw(sum0); use List::MoreUtils qw(slide); sub ascii_differences_sum_slide { sum0 slide {abs(ord($b) - ord($a))} split '',$_[0] }# A fanciful creation by fans, combining various Elvish elements from Tolkien's work. my $input_string = "Aearenuialinorosinaiantirnoitisirsiensinoit";# Benchmark all three methods timethese(1000000, { 'Using split_1' => sub { ascii_differences_sum_split_1($input_string) }, 'Using split_2' => sub { ascii_differences_sum_split_2($input_string) }, 'Using slide' => sub { ascii_differences_sum_slide($input_string) }, }); =beginResults: =cut
Benchmark: timing 1000000 iterations of Using slide, Using split_1, Using split_2... Using slide: 7 wallclock secs ( 6.55 usr + 0.00 sys = 6.55 CPU) @ 152671.76/s (n=1000000) Using split_1: 7 wallclock secs ( 6.87 usr + 0.00 sys = 6.87 CPU) @ 145560.41/s (n=1000000) Using split_2: 6 wallclock secs ( 5.76 usr + 0.00 sys = 5.76 CPU) @ 173611.11/s (n=1000000)
#!/usr/bin/perl use strict; use warnings; sub ascii_differences_sum_split_2_alt { my ( $t, @list ) = ( 0, split(//, $_[0]) ); my $f = ord( shift(@list) ); for (@list) { $t += abs( $f - ord($_) ); $f = ord($_); } return($t); }