30
\$\begingroup\$

Your network scanning tool is annoyingly picky about input, and immediately crashes if you feed it an IPv4 address that contains improper characters or isn't properly formatted.

An IPv4 address is a 32-bit numeric address written as four numbers separated by periods. Each number can be zero to 255.

We need to write a tool to pre-validate the input to avoid those crashes, and our specific tool is picky: A valid format will look like a.b.c.d where a, b, c and d:

  • Can be a 0 or a natural number with no leading zeros.
  • Should be between 0 - 255 (inclusive).
  • Should not contain special symbols like +, -, ,, and others.
  • Should be decimal (base 10)

Input: A string

Output: Truthy or Falsey value (arbitrary values also accepted)

Test Cases:

Input            |  Output  |  Reason
                 |          |
- 1.160.10.240   |  true    |
- 192.001.32.47  |  false   |  (leading zeros present)
- 1.2.3.         |  false   |  (only three digits)
- 1.2.3          |  false   |  (only three digits)
- 0.00.10.255    |  false   |  (leading zeros present)
- 1.2.$.4        |  false   |  (only three digits and a special symbol present)
- 255.160.0.34   |  true    |
- .1.1.1         |  false   |  (only three digits)
- 1..1.1.1       |  false   |  (more than three periods)
- 1.1.1.-0       |  false   |  (special symbol present)
- .1.1.+1        |  false   |  (special symbol present)
- 1 1 1 1        |  false   |  (no periods)
- 1              |  false   |  (only one digit)
- 10.300.4.0     |  false   |  (value over 255)
- 10.4F.10.99    |  false   |  (invalid characters)
- fruit loops    |  false   |  (umm...)
- 1.2.3.4.5      |  false   |  (too many periods/numbers)
- 0.0.0.0        |  true    |
- 0.0 0.0.       |  false   |  (periods misplaced)
- 1.23..4        |  false   |  (a typo of 1.2.3.4)
- 1:1:1:1:1:1:1:1|  false   |  (an IPv6 address, not IPv4)

This is , so fewest bytes will win!

Note for the users - if anyone wants to add some test-cases, they're welcomed (by suggesting an edit).

\$\endgroup\$
16
  • 10
    \$\begingroup\$ Suggest testcases: 1.1.1.1.1, 1.1.1.1., .1.1.1, 1..1.1, 1..1.1.1, 1.1.1.0, 1.1.1.-0, 1.1.1.+1, 1.1.1.1E1, 1.1.1.256, 1.1.1.0x1, 255.255.255.255, 0.0.0.0, 'or 1=1--, <empty string>, 1 1 1 1, 1,1,1,1. \$\endgroup\$
    – tsh
    Commented Oct 22, 2018 at 9:11
  • 5
    \$\begingroup\$ Suggest adding test cases "1.2.3.4.5" (to rule out too long IPs) and "999.0.0.0" (to rule out too large IPs). \$\endgroup\$ Commented Oct 22, 2018 at 15:50
  • 5
    \$\begingroup\$ Possibly slightly picky, but you should probably refer to "IPv4 addresses" rather than "IP addresses" - or at least, mention somewhere that you just mean IPv4 addresses - otherwise 1234:5678::1 ought to be a valid IP address (whereas from the description it's clear that that's not intended :) \$\endgroup\$
    – psmears
    Commented Oct 23, 2018 at 15:51
  • 4
    \$\begingroup\$ @Criggie The premise isn't to actually check all real IP4 rules (like the ones you mentioned), it's to ensure that the input string doesn't crash some other (presumably badly written) app that only allows input in a very specific form. Also, we're not going to change the rules of a challenge that already has 30+ answers. \$\endgroup\$
    – BradC
    Commented Oct 23, 2018 at 19:03
  • 2
    \$\begingroup\$ @Criggie Worth noting that the RFC declares that "Addresses are fixed length of four octets". I think the fringe cases you're referencing are more specialized than this challenge. \$\endgroup\$
    – Poke
    Commented Oct 23, 2018 at 19:12

41 Answers 41

1
2
1
\$\begingroup\$

JavaScript, 89 bytes

(_,r=`(${[...Array(256).keys()].join`|`})`)=>RegExp(`^${(r+'\\.').repeat(3)+r}$`).test(_)

Try it online!

Create RegExp capture groups from indexes of an array having length 256 for range 0-255 joined with | and followed by escaped . character (^(0|1...|255)\.(0|1...|255)\.(0|1...|255)\.(0|1...|255)$) repeated 3 times closing with joined array followed by $ to match end of string, return true or false result of input passed to RegExp.prototype.test().

\$\endgroup\$
1
\$\begingroup\$

R, 59 bytes

Passes special cases not in test with periods at start/end

function(s)length(a<-scan(,t=s,s,,,"."))==4&all(a%in%0:255)

Try it online!

\$\endgroup\$
1
\$\begingroup\$

C (gcc), 287 197 bytes

#import<regex.h>
g;f(char*s){regex_t r;g=regcomp(&r,"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$",1);g=regexec(&r,s,0,0,0);return !g;}

Try it online!

Thanks to Logern for the big save !

\$\endgroup\$
2
  • \$\begingroup\$ 197 bytes Try it online!Saved bytes by removing types, replacing REG_EXTENDED with its int value, removing some of the includes, instead using import, renaming variables and removing the ternary in the return. \$\endgroup\$
    – user36046
    Commented Oct 22, 2018 at 23:13
  • \$\begingroup\$ 188 bytes \$\endgroup\$
    – ceilingcat
    Commented Aug 16, 2019 at 5:42
1
\$\begingroup\$

Ruby, 123 107 bytes

Try it online!

a=gets.chomp
e=a.split'.'
(p 0;exit)if(e.map(&:to_i).join'.')!=a
p(e.all?{|i|(0..255)===i.to_i}&&e.size==4)

This could definitely be shorter, probably with a regex of some sort, but I wanted to do it without a regex.

Thanks to MegaTom for Array#all?

0 or false is falsy; true is truthy.

Explanation:

The input is taken from stdin. It's split into an array of the numbers (as strings) on the periods.

If the array isn't the same as it is with the elements converted to numbers and back to strings, the program outputs 0 and exits. This eliminates cases with leading zeros and illegal characters.

The array is converted to an array of true/false values representing whether the value is between 0 and 255, inclusive.

true is outputted if the array is only true values, meaning that all the numbers were between 0 and 255, and only if it has exactly 4 elements, meaning that there were 4 original numbers. false is outputted otherwise, meaning invalid numbers (higher than 255) or too many numbers.

\$\endgroup\$
4
  • \$\begingroup\$ Hello and welcome to PPCG. Could you possibly provide a link to an online interpreter for ease of verifying your solution? \$\endgroup\$ Commented Jan 27, 2019 at 13:15
  • \$\begingroup\$ I've added a TIO link. The default input is 255.255.255.255. \$\endgroup\$ Commented Jan 28, 2019 at 2:52
  • \$\begingroup\$ I think the all? method could make this code a good bit shorter. \$\endgroup\$
    – MegaTom
    Commented Jan 28, 2019 at 4:59
  • \$\begingroup\$ Thanks! I didn't think of that. \$\endgroup\$ Commented Jan 28, 2019 at 5:03
1
\$\begingroup\$

APL(NARS), 45 chars

{'...'≢⍵∼⎕D:0⋄4≠+/255≥⍎¨a←⍵⊂⍨⍵≠'.':0⋄a≡⍕¨⍎¨a}

test

  f←{'...'≢⍵∼⎕D:0⋄4≠+/255≥⍎¨a←⍵⊂⍨⍵≠'.':0⋄a≡⍕¨⍎¨a}  
  f '1.160.10.240'   
1
  f '192.001.32.47' 
0
  f '1.2.3.'
0
  f '1.2.3'
0
\$\endgroup\$
0
\$\begingroup\$

Batch, 53 bytes

@(ping -4 %1&echo g 255.255.255.255 w)|find/c"g %1 w"

Disconnect your Internet connection first to avoid the standard loophole.

I can't find information on how to avoid ^".

\$\endgroup\$
1
  • \$\begingroup\$ Deleted cuz can't handle 255.255.255.255 \$\endgroup\$
    – l4m2
    Commented Oct 22, 2018 at 12:03
0
\$\begingroup\$

APL(NARS) 50 chars, 100 bytes

{'...'≢⍵∼⎕D:0⋄4≠≢w←⍵⊂⍨⍵≠'.':0⋄w≢⍕¨m←⍎¨w:0⋄256>⌈/m}

test:

  p←{'...'≢⍵∼⎕D:0⋄4≠≢w←⍵⊂⍨⍵≠'.':0⋄w≢⍕¨m←⍎¨w:0⋄256>⌈/m}
  {⍞←'[',⍵,'=',(p ⍵),']'⋄⍬}¨a 
[1.160.10.240= 1 ][192.001.32.47= 0 ][1.2.3.= 0 ][0.00.10.255= 0 ][1.2.$.4= 0 ][255.160.0.34= 1 ][.1.1.1= 0 ][1..1.1.1= 0 ][1.1.1.-0= 0 ][.1.1.+1= 0 ][1 1 1 1= 0 ][1= 0 ][10.300.4.0= 0 ][10.4F.10.99= 0 ][fruit loops= 0 ][1.2.3.4.5= 0 ][0.0.0.0= 1 ][0.0 0.0.= 0 ][1.23..4= 0 ][1:1:1:1:1:1:1:1= 0 ]  
\$\endgroup\$
0
\$\begingroup\$

Scala, 87 bytes

A port of @Olivier Grégoire's answer.

Try it online!

val f:String=>Boolean=s=>("." + s).matches("(\\.(25[0-5]|(2[0-4]|1\\d|[1-9])?\\d)){4}")
\$\endgroup\$
0
\$\begingroup\$

Thunno 2, 15 bytes

'./Ẋl4=ɠL€ṘxƇp&

Try it online!

Explanation

'./Ẋl4=ɠL€ṘxƇp&  '# Implicit input
'./              '# Split the input on "."s
   Ẋ              # Store this in x without popping
    l4=           # Check if the length equals 4
       ɠL         # Push the range [0..255]
         €Ṙ       # Convert each to a string
           xƇp    # Check if each of the values in x
                  # is in this list of strings
                  # (NOTE: this checks three things at once:
                  #   1. all the parts are numbers
                  #   2. all of them are in the range [0..255]
                  #   3. none of them have leading zeros)
              &   # Check if both things are true
                  # Implicit output
\$\endgroup\$
0
\$\begingroup\$

Go, 81 bytes

import."net/netip"
func f(s string)bool{a,e:=ParseAddr(s)
return e==nil&&a.Is4()}

Attempt This Online!

Uses the net/netip package from the standard library.

Go, 119 bytes

import."regexp"
func f(s string)bool{return MustCompile(`^(\.(25[0-5]|(2[0-4]|1\d|[1-9])?\d)){4}$`).MatchString("."+s)}

Attempt This Online!

Using the regex from @Olivier Grégoire's post.

\$\endgroup\$
-1
\$\begingroup\$

PHP, 27 26 24 Bytes

<?=+!!ip2long($argv[1]);

Based on @rexkogitans and @nwellnhof solutions Fails for 0.0.0.0 because PHP internal function 0.0.0.0 is not considered a valid IP address Try it!

\$\endgroup\$
1
2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.