DEV Community

Simon Green
Simon Green

Posted on

Weekly Challlenge: The subnet detector

Weekly Challenge 363

Each week Mohammad S. Anwar sends out The Weekly Challenge, a chance for all of us to come up with solutions to two weekly tasks. My solutions are written in Python first, and then converted to Perl. Unless otherwise stated, CoPilot (and other AI tools) have NOT been used to generate the solution. It's a great way for us all to practice some coding.

Challenge, My solutions

Task 1: String Lie Detector

Task

You are given a string.

Write a script that parses a self-referential string and determines whether its claims about itself are true. The string will make statements about its own composition, specifically the number of vowels and consonants it contains.

My solution

This was relatively straight forward in Python. I took the following steps:

  1. Use a regular expression to extract the necessary parts of the input_string, and store this as the value match.
  2. Count the number of vowels and consonants in the first value and store it as vowel_count and const_count.
  3. Use the word2num module to convert the numbers in input_string to integers, stored as expected_vowel and expected_const.
  4. Compare the count and expected values match, and return the result.
import re
from word2num import word2num

def string_lie_detector(input_string: str) -> bool:
    match = re.match(
        r"(\w+) . (\w+) vowels? and (\w+) consonants?", input_string)
    if not match:
        raise ValueError("Input string not in expected format")

    vowel_count = 0
    const_count = 0
    for c in match.group(1).lower():
        if c in "aeiou":
            vowel_count += 1
        else:
            const_count += 1

    expected_vowel = word2num(match.group(2))
    expected_const = word2num(match.group(3))

    return vowel_count == expected_vowel and const_count == expected_const
Enter fullscreen mode Exit fullscreen mode

The Perl solution is a little more complex. Maybe my Google-foo isn't up to scratch (and I don't use Copilot when working on solutions) that there doesn't appear to be a CPAN module that will convert words into numbers. As this is a coding exercise only I have a hash called %word2num that maps words to number (from zero to twenty).

The next problem is four of the examples use a long dash as the separator. This is a UTF-8 character. The result of perl -E 'say length("—")' is 3. After numerous searches of the Internet, it turns out I need to include use utf8:all in the code. With this change, I get the expected result of 1.

The rest of the code follows the same logic as the Python solution.

use utf8::all;

sub main ($input_string) {
    my %word2num = (qw/
        zero 0 one 1 two 2 three 3 four 4 five 5 six 6 seven 7 eight 8
        nine 9 ten 10 eleven 11 twelve 12 thirteen 13 fourteen 14
        fifteen 15 sixteen 16 seventeen 17 eighteen 18 nineteen 19 twenty 20
    /);

    my ( $word, $v, $c ) =
      ( $input_string =~ /(\w+) . (\w+) vowels? and (\w+) consonants?/ );

    if ( !$word ) {
        die "Input string not in expected format\n";
    }

    my $vowel_count = 0;
    my $const_count = 0;
    foreach my $c ( split //, lc($word) ) {
        if ( index( "aeiou", $c ) == -1 ) {
            $const_count++;
        }
        else {
            $vowel_count++;
        }
    }

    my $expected_vowel = $word2num{ lc $v } // die "Don't know what $v is\n";
    my $expected_const = $word2num{ lc $c } // die "Don't know what $c is\n";

    my $truth =
      ( $vowel_count == $expected_vowel and $const_count == $expected_const );
    say $truth ? 'true' : 'false';
}
Enter fullscreen mode Exit fullscreen mode

Examples

There was an issue with the examples, and I raised a pull request to fix it.

$ ./ch-1.py "aa — two vowels and zero consonants"
True

$ ./ch-1.py "iv — one vowel and one consonant"
True

$ ./ch-1.py "hello - three vowels and two consonants"
False

$ ./ch-1.py "aeiou — five vowels and zero consonants"
True

$ ./ch-1.py "aei — three vowels and zero consonants"
True
Enter fullscreen mode Exit fullscreen mode

Task 2: Subnet Sheriff

Task

You are given an IPv4 address and an IPv4 network (in CIDR format).

Write a script to determine whether both are valid and the address falls within the network. For more information see the Wikipedia article.

My solution

This one was the easier of the two to complete. Maybe because I have worked at many IPSs in the past :-)

Python has the ipaddress module which makes it easy to confirm if an IPv4 address is in a particular IP address block.

I use a try/except block to handle situations (like the second example) where the IP address or net block is invalid. This follows the Python philosophy of Easier to Ask for Forgiveness than Permission.

import ipaddress

def subnet_sheriff(ip_addr: str, domain: str) -> bool:
    try:
        return ipaddress.IPv4Address(ip_addr) in ipaddress.IPv4Network(domain)
    except ipaddress.AddressValueError:
        return False
Enter fullscreen mode Exit fullscreen mode

Perl has the Net::IP module in CPAN that performs similar functionality. If the IP address or net block is invalid, the variable will be undef, and the else block will be used.

use Net::IP;

sub main ( $ip_addr, $domain ) {
    my $addr = Net::IP->new($ip_addr);
    my $block = Net::IP->new($domain);
    if ( $addr and $block ) {
        my $overlaps = ( $addr->overlaps($block) != $IP_NO_OVERLAP );
        say $overlaps  ? 'true' : 'false';
    }
    else {
        say 'false';
    }
}
Enter fullscreen mode Exit fullscreen mode

Examples

$ ./ch-2.py 192.168.1.45 192.168.1.0/24
True

$ ./ch-2.py 10.0.0.256 10.0.0.0/24
False

$ ./ch-2.py 172.16.8.9 172.16.8.9/32
True

$ ./ch-2.py 172.16.4.5 172.16.0.0/14
True

$ ./ch-2.py 192.0.2.0 192.0.2.0/25
True

$ ./ch-2.py 1.1.1.1 10.0.0.0/8
False
Enter fullscreen mode Exit fullscreen mode

Top comments (0)