-3

I'm trying to write a program that prints the invalid part or parts of an IPv4 address from terminal input.

Here is my code:

package chapter4

import (
    "bufio"
    "fmt"
    "os"
    "regexp"
    "strings"
    "time"
)

func IPV4() {
    var f *os.File
    f = os.Stdin
    defer f.Close()

    scanner := bufio.NewScanner(f)
    fmt.Println("Exercise 1, Chapter 4 - Detecting incorrect parts of IPv4 Addresses, enter an address!")
    for scanner.Scan() {

        if scanner.Text() == "STOP" {
            fmt.Println("Initializing Level 4...")
            time.Sleep(5 * time.Second)
            break
        }
        expression := "(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])"
        matchMe, err := regexp.Compile(expression)
        if err != nil {
            fmt.Println("Could not compile!", err)
        }

        s := strings.Split(scanner.Text(), ".")

        for _, value := range s {
            fmt.Println(value)
            str := matchMe.FindString(value)
            if len(str) == 0 {
                fmt.Println(value)
            }
        }

    }
}

My thought process is that for every terminal IP address input, I split the string by '.'

Then I iterate over the resulting []string and match each value to the regular expression.

For some reason the only case where the regex expression doesn't match is when there are letter characters in the input. Every number, no matter the size or composition, is a valid match for my expression.

I'm hoping you can help me identify the problem, and if there's a better way to do it, I'm all ears. Thanks!

MjBVala
  • 137
  • 3
  • 9
  • I guess that you must use a regex for this because it is an exercise? If it was for something real I'd split on dots, verify I had four parts, convert each part to a number, and verify the number was between 0 and 255. – Zan Lynx Aug 10 '19 at 19:08
  • 1
    Also please get out of the habit of compiling regular expressions inside functions, and especially don't do it inside loops. See that `MustCompile` function which will panic if it fails? Stick that outside your function in a variable assignment, then it will run one time at program start. – Zan Lynx Aug 10 '19 at 19:12
  • Yes it is an exercise, but thanks for explaining how you'd do it, seems like a much simpler solution. I used compile because as far as I know it doesn't panic, like mustCompile. Would a global variable still be the way to go? – MjBVala Aug 11 '19 at 02:30
  • If MustCompile panics then your regular expression is bad. That means a panic is what you want since your program is broken. – Zan Lynx Aug 11 '19 at 04:25

2 Answers2

0

I am pretty sure that your expression needs anchors or the last part of it will match any single digit and succeed. Try using ^ on the front and $ on the back.

Zan Lynx
  • 53,022
  • 10
  • 79
  • 131
  • Hi yes, thank you this worked. Is there a difference between anchoring every piece, like so ``(^25[0-5]$|^2[0-4][0-9]$|^1[0-9][0-9]$|^[1-9]?[0-9]$)`` versus just the front and back of the parenthesis? – MjBVala Aug 11 '19 at 02:27
0

Maybe, this expression might be closer to what you might have in mind:

^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$

Test

package main

import (
    "regexp"
    "fmt"
)

func main() {
    var re = regexp.MustCompile(`(?m)^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$`)
    var str = `127.0.0.1
192.168.1.1
192.168.1.255
255.255.255.255
0.0.0.0
1.1.1.01

30.168.1.255.1
127.1
192.168.1.256
-1.2.3.4
3...3`

    for i, match := range re.FindAllString(str, -1) {
        fmt.Println(match, "found at index", i)
    }
}

The expression is explained on the top right panel of regex101.com, if you wish to explore/simplify/modify it, and in this link, you can watch how it would match against some sample inputs, if you like.

Reference:

Validating IPv4 addresses with regexp

RegEx Circuit

jex.im visualizes regular expressions:

enter image description here

Emma
  • 27,428
  • 11
  • 44
  • 69