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

25
\$\begingroup\$

X86_64 machine code: 18 16 bytes

Edit: This answer doesn't quite work, as

  1. I am using inet_pton from the standard C libraries, which means I need the extern. I didn't include the extern in my byte count though.
  2. I used the red zone as a result for the actual address, but called a function which also could've used the red zone. It fortunately doesn't on my machine, but some odd standard library build might use it which could cause undefined behavior.

And yeah, the whole thing is pretty much being done by an already written function

Anyway, this is what I got: 48 89 fe 6a 02 5f 48 8d 54 24 80 e9 00 00 00 00

Assembly:

section .text
    extern inet_pton
    global ipIsValid

ipIsValid:
    mov rsi, rdi
    ;mov rdi, 2 ; change to 10 for ipv6
    push 2
    pop rdi ; thank you peter
    lea rdx, [rsp - 128]
    jmp inet_pton

Explanation:

Take a look at inet_pton(3). It takes a string IP address and puts it in a buffer you can use with struct sockaddr. It takes 3 arguments: the address family (AF_INET (ipv4), 2, or AF_INET6 (ipv6), 10), the ip address's string, and a pointer to the output. It returns 1 on success, 0 for an invalid address, or -1 for when the address family is neither AF_INET or AF_INET6 (which will never occur because I'm passing a constant to it).

So I simply move the string to the register for the second argument, set the first register to 2, and set the third register to the red zone (128 bytes below the stack pointer) since I don't care about the result. Then I can simply jmp to inet_pton and let that return straight to the caller!

I spun up this quick test program to test your cases:

#include <stdio.h>
#include <arpa/inet.h>
#include <netinet/ip.h>

extern int ipIsValid(char *);

int main(){
    char *addresses[] = {
        "1.160.10.240",
        "192.001.32.47",
        "1.2.3.",
        "1.2.3",
        "0.00.10.255",
        "1.2.$.4",
        "255.160.0.34",
        ".1.1.1",
        "1..1.1.1",
        "1.1.1.-0",
        ".1.1.+1",
        "1 1 1 1",
        "1",
        "10.300.4.0",
        "10.4F.10.99",
        "fruit loops",
        "1.2.3.4.5",
        NULL
    };

    for(size_t i = 0; addresses[i] != NULL; ++i){
        printf("Address %s:\t%s\n", addresses[i],
            ipIsValid(addresses[i]) ? "true" : "false");
    }
    return 0;
}

Assemble with nasm -felf64 assembly.asm, compile with gcc -no-pie test.c assembly.o, and you'll get:

Address 1.160.10.240:   true
Address 192.001.32.47:  false
Address 1.2.3.: false
Address 1.2.3:  false
Address 0.00.10.255:    false
Address 1.2.$.4:    false
Address 255.160.0.34:   true
Address .1.1.1: false
Address 1..1.1.1:   false
Address 1.1.1.-0:   false
Address .1.1.+1:    false
Address 1 1 1 1:    false
Address 1:  false
Address 10.300.4.0: false
Address 10.4F.10.99:    false
Address fruit loops:    false
Address 1.2.3.4.5:  false

I could make this much smaller if the caller was supposed to pass AF_INET or AF_INET6 to the function

\$\endgroup\$
11
  • 5
    \$\begingroup\$ I love that you did this in asm. And the fact you explained it to those who might not understand it (as well as test code) is even better. Which is not to say that I could have done it in asm; far too many years have passed but I remember enough to see exactly what your explanation (and therefore process) is saying (does). Good work. \$\endgroup\$
    – Pryftan
    Commented Oct 23, 2018 at 13:17
  • 5
    \$\begingroup\$ e9 00 00 00 00 is a jmp near $+5, not a jmp inet_pton. If you provide opcode, you should include the including inet_pton part, not leave a blank \$\endgroup\$
    – l4m2
    Commented Oct 23, 2018 at 16:58
  • 1
    \$\begingroup\$ 15 bytes-TIO 32bit x86 \$\endgroup\$
    – user36046
    Commented Oct 23, 2018 at 17:26
  • 4
    \$\begingroup\$ you should include the extern in the answer title, since the program requires it and it is not available on all platforms. \$\endgroup\$
    – qwr
    Commented Oct 23, 2018 at 20:07
  • 1
    \$\begingroup\$ the "mov rdi,2" can be "push 2/pop rdi" for -2 bytes. Note also that the disassembly is wrong or the code is wrong. It's either "mov edi" (not rdi) or there's a prefix missing. \$\endgroup\$ Commented Oct 26, 2018 at 18:42
13
\$\begingroup\$

Java (JDK), 63 bytes

s->("."+s).matches("(\\.(25[0-5]|(2[0-4]|1\\d|[1-9])?\\d)){4}")

Try it online!

Credits

\$\endgroup\$
5
  • \$\begingroup\$ You forgot to remove the trailing semi-colon. ;) And I can verify it works for all test cases, including those in the comments. Will see if I see some things to golf. \$\endgroup\$ Commented Oct 22, 2018 at 10:00
  • 3
    \$\begingroup\$ Failed on .1.2.3.4 \$\endgroup\$
    – l4m2
    Commented Oct 22, 2018 at 10:01
  • \$\begingroup\$ Is it allowed to use boolean when explictly require 0/1? \$\endgroup\$
    – l4m2
    Commented Oct 22, 2018 at 10:18
  • 1
    \$\begingroup\$ @l4m2 The original question had Valid/Invalid. So I assume any truthy/falsey value is acceptable here. \$\endgroup\$ Commented Oct 22, 2018 at 10:20
  • \$\begingroup\$ Output: 0 or 1 and Java has no auto bool->int \$\endgroup\$
    – l4m2
    Commented Oct 22, 2018 at 10:21
12
\$\begingroup\$

JavaScript (Node.js), 43 bytes

x=>x.split`.`.map(t=>[t&255]==t&&[])==`,,,`

Try it online!

JavaScript (Node.js), 46 bytes

x=>x.split`.`.every(t=>k--&&[t&255]==t,k=4)*!k

Try it online!

used Arnauld's part

JavaScript (Node.js), 54 53 51 bytes

x=>x.split`.`.every(t=>k--*0+t<256&[~~t]==t,k=4)*!k

Try it online!

-2B for 0+t<256, -1B from Patrick Stephansen, +1B to avoid input 1.1.1.1e-80

RegExp solution 5854 bytes

s=>/^((2(?!5?[6-9])|1|(?!0\d))\d\d?\.?\b){4}$/.test(s)

Thank Deadcode for 3 bytes

\$\endgroup\$
11
  • \$\begingroup\$ I have added some test cases! \$\endgroup\$
    – vrintle
    Commented Oct 22, 2018 at 6:22
  • \$\begingroup\$ This gives truthy for 0.0.0.0. Everything else seems to work fine. \$\endgroup\$ Commented Oct 22, 2018 at 9:35
  • 1
    \$\begingroup\$ @KevinCruijssen 0.0.0.0 is here true one. Just why SQL injection is here? \$\endgroup\$
    – l4m2
    Commented Oct 22, 2018 at 9:37
  • \$\begingroup\$ Ah wait, I misinterpret the sentence in the challenge description. 0.0.0.0 is indeed truthy. That will golf my answer as well.. (And what do you mean by SQL injection? :S The link is to TIO with ALL test cases.) \$\endgroup\$ Commented Oct 22, 2018 at 9:40
  • 1
    \$\begingroup\$ @l4m2 I added it since we need some testcases that even not looks like an IP address. \$\endgroup\$
    – tsh
    Commented Oct 22, 2018 at 9:45
11
\$\begingroup\$

PHP, 39 36 bytes

<?=+!!filter_var($argv[1],275,5**9);

Try it online!

275 resembles the constant FILTER_VALIDATE_IP

5**9 is being used instead of the constant FILTER_FLAG_IPV4. This is sufficient, because 5**9 & FILTER_FLAG_IPV4 is truthy, which is exactly what PHP does in the background, as Benoit Esnard pointed out.

Here, filter_var returns the first argument, if it's a valid IPv4 address, or false if it's not. With +!!, we produce the output required by the challenge.

\$\endgroup\$
6
  • 3
    \$\begingroup\$ Using 5**9 instead of 1048576 saves 3 bytes here: PHP uses & to test the IPv4 / IPv6 flags, so any number between 1048576 and 2097151 is valid. \$\endgroup\$ Commented Oct 22, 2018 at 10:12
  • \$\begingroup\$ I hereby downvote your answer for being (basically) my answer: codegolf.stackexchange.com/a/174470/14732 which was written at 2018-10-22 09:17:34UTC while yours was written on 2018-10-22 09:21:55UTC. Even if I revert the 1-byte optimization given by @BenoitEsnard, my answer is exactly the same as yours in functionality. \$\endgroup\$ Commented Oct 22, 2018 at 15:06
  • 2
    \$\begingroup\$ I have to apologise, I didn't see your answer, though at the time I was composing it, there was no submission in PHP on this question (as you said, the time difference is less than five minutes). \$\endgroup\$
    – oktupol
    Commented Oct 22, 2018 at 15:16
  • \$\begingroup\$ I know, and I understand it. I only noticed yours just now. I can roll back mine, and you keep the optimization. But I don't know if it makes the answer be different enough from eachother. \$\endgroup\$ Commented Oct 22, 2018 at 15:33
  • 18
    \$\begingroup\$ @IsmaelMiguel I wouldn't downvote somebody for that if it's plausible yours wasn't there when they started. With a 5 minute difference, not only is it plausible, it's almost certainly the case, which is apparent even without the author saying so himself. \$\endgroup\$ Commented Oct 22, 2018 at 17:47
11
\$\begingroup\$

PHP, 36 Bytes

echo(ip2long($argv[1])===false?0:1);

ip2long is a well-known built-in function.

\$\endgroup\$
10
  • 3
    \$\begingroup\$ 29 bytes \$\endgroup\$
    – nwellnhof
    Commented Oct 22, 2018 at 10:53
  • \$\begingroup\$ This seems to use uncodumented features present in newer versions (I presume it is from PHP7+). Keep in mind that, for PHP 4 and 5, this does accept incomplete IPs. \$\endgroup\$ Commented Oct 22, 2018 at 15:10
  • \$\begingroup\$ 27 bytes \$\endgroup\$
    – Mark
    Commented Oct 22, 2018 at 17:39
  • \$\begingroup\$ codegolf.meta.stackexchange.com/a/7146/12130 \$\endgroup\$ Commented Oct 22, 2018 at 18:02
  • 1
    \$\begingroup\$ This will give success if you feed it any integer, such as 1 , 2 , etc. Don't think it should. And also if you feed it something as 100.100.100 \$\endgroup\$
    – nl-x
    Commented Oct 24, 2018 at 9:52
10
\$\begingroup\$

Perl 6, 22 21 20 bytes

-1 byte thanks to Phil H.

{?/^@(^256)**4%\.$/}

Try it online!

Explanation

{                  }  # Anonymous Block
  /               /   # Regex match
   ^             $    # Anchor to start/end
    @(    )           # Interpolate
      ^256            #   range 0..255,
                      #   effectively like (0|1|2|...|255)
           **4        # Repeated four times
              %\.     # Separated by dot
 ?                    # Convert match result to Bool
\$\endgroup\$
3
  • 3
    \$\begingroup\$ Man, I need to spend more time figuring out Perl 6's regexes. I had no either the % modifier existed. I wonder if it tries to checks all 256**4 possibilities? \$\endgroup\$
    – Jo King
    Commented Oct 22, 2018 at 10:57
  • 1
    \$\begingroup\$ Instead of <{^256}> you can just convert the range to an array @(^256) for -1 char TIO. By changing the code block to an array it also gets enormously faster (0.4s instead of >30). \$\endgroup\$
    – Phil H
    Commented Oct 25, 2018 at 13:37
  • \$\begingroup\$ @PhilH Cool, thanks. I tried $(^256) but now I realize why this didn't work. \$\endgroup\$
    – nwellnhof
    Commented Oct 25, 2018 at 15:11
9
\$\begingroup\$

05AB1E, 26 24 23 22 23 17 bytes

'.¡DgsAì₅ÝAìÃg4)Ë

-1 byte thanks to @Emigna.
+1 byte for bugfixing test case 1.1.1.1E1 incorrectly returning a truthy result.

Try it online or verify all test cases.

Explanation:

'.¡          '# Split the (implicit) input-string on "."
   D          # Duplicate this list
    g         # Pop and push the length of this copy
   s          # Swap so the list is at the top again
    Aì        # Prepend the alphabet before each item
      ₅Ý      # Push a list in the range [0,255]
        Aì    # Prepend the alphabet before each integer here as well
          Ã   # Only keep those items from the first list
           g  # Pop and push its length as well
   4          # Push a 4
    )         # Wrap all three values on the stack into a list
     Ë        # Check that all three are the same (aka all three are 4s)
              # (after which the result is output implicitly)

Prepending the alphabet is necessary, because in 05AB1E, "0", "00", "0e0", "5E0", "-0" etc. are all the same 'integer' 0.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ You should be able to use Ā instead of <d \$\endgroup\$
    – Emigna
    Commented Oct 22, 2018 at 9:14
  • \$\begingroup\$ @MagicOctopusUrn I'm afraid it fails for 1.1.1.1E1, 1..1.1.1, 1.1.1.1., 192.00.0.255, and 0.00.10.255. (PS: I've fixed the 1.1.1.1E1 by adding the þ to the join-and-equal check.) \$\endgroup\$ Commented Oct 22, 2018 at 12:32
  • \$\begingroup\$ Fair enough, figured I missed something. \$\endgroup\$ Commented Oct 22, 2018 at 12:33
  • \$\begingroup\$ @MagicOctopusUrn The main issue is 05AB1E seeing numbers with leading 0s equal to those without, even as string. Which is why I use the DïþJsJQ check where ï cast it to int to remove leading 0s, and þ only leaves digits removing things like E, -, etc. :) The is for test case 0.00.10.255, since 00010255 and 0010255 would be equal. \$\endgroup\$ Commented Oct 22, 2018 at 12:34
  • \$\begingroup\$ Yeah I went through the same nonsense, the reversal of all numbers worked pretty well though, except for those cases. Interesting when features beneficial for some problems become almost bug-like for others. \$\endgroup\$ Commented Oct 22, 2018 at 12:35
6
\$\begingroup\$

Python 3: 81 78 70 69 66 bytes

['%d.%d.%d.%d'%(*x.to_bytes(4,'big'),)for x in range(16**8)].count

Loop over all possible IPv4 addresses, get the string representation and compare it to the input. It uh... takes a while to run.

EDIT: Removed 3 bytes by switching from full program to anonymous function.

EDIT2: Removed 8 bytes with help from xnor

EDIT3: Removed 1 byte by using an unpacked map instead of list comprehension

EDIT4: Removed 3 bytes by using list comprehension instead of the ipaddress module

\$\endgroup\$
2
  • 2
    \$\begingroup\$ I think your anonymous function can just be [str(ip_address(x))for x in range(256**4)].count. Also, 256**4 can be 16**8. \$\endgroup\$
    – xnor
    Commented Oct 22, 2018 at 23:45
  • \$\begingroup\$ I like the extemely golfy while practically unusable approach :) \$\endgroup\$
    – movatica
    Commented Feb 28, 2021 at 12:11
6
\$\begingroup\$

PowerShell, 59 51 49 bytes

-8 bytes, thanks @AdmBorkBork

-2 bytes, true or false allowed by author

try{"$args"-eq[IPAddress]::Parse($args)}catch{!1}

Test script:

$f = {

try{"$args"-eq[IPAddress]::Parse($args)}catch{!1}

}

@(
    ,("1.160.10.240" , $true)
    ,("192.001.32.47" , $false)
    ,("1.2.3." , $false)
    ,("1.2.3" , $false)
    ,("0.00.10.255" , $false)
    ,("192.168.1.1" , $true)
    ,("1.2.$.4" , $false)
    ,("255.160.0.34" , $true)
    ,(".1.1.1" , $false)
    ,("1..1.1.1" , $false)
    ,("1.1.1.-0" , $false)
    ,("1.1.1.+1" , $false)
    ,("1 1 1 1" , $false)
    ,("1"            ,$false)
    ,("10.300.4.0"   ,$false)
    ,("10.4F.10.99"  ,$false)
    ,("fruit loops"  ,$false)
    ,("1.2.3.4.5"    ,$false)

) | % {
    $s,$expected = $_
    $result = &$f $s
    "$($result-eq$expected): $result : $s"
}

Output:

True: True : 1.160.10.240
True: False : 192.001.32.47
True: False : 1.2.3.
True: False : 1.2.3
True: False : 0.00.10.255
True: True : 192.168.1.1
True: False : 1.2.$.4
True: True : 255.160.0.34
True: False : .1.1.1
True: False : 1..1.1.1
True: False : 1.1.1.-0
True: False : 1.1.1.+1
True: False : 1 1 1 1
True: False : 1
True: False : 10.300.4.0
True: False : 10.4F.10.99
True: False : fruit loops
True: False : 1.2.3.4.5

Explanation:

The script tries to parse an argument string, to construct a .NET object, IPAddress.

  • return $true if object created and the argument string is equal to a string representation of the object (normalized address by object.toString())
  • return $false otherwise

PowerShell, 59 56 54 bytes, 'don't use a .NET lib' alternative

-3 bytes, true or false allowed by author

-2 bytes, thanks to @Deadcode for the cool regexp.

".$args"-match'^(\.(2(?!5?[6-9])|1|(?!0\B))\d\d?){4}$'

Try it online!

Thanks @Olivier Grégoire for the original regular expression.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ You shouldn't need to call |% t*g since PowerShell will automatically cast the right-hand-side of -eq as a string, because the left-hand-side is a string. -- try{+("$args"-eq[IPAddress]::Parse($args))}catch{0} \$\endgroup\$ Commented Oct 22, 2018 at 16:05
  • \$\begingroup\$ You can carve 2 bytes from the "don't use a .NET lib" version by using my regex (adapted to the insert-a-period trick, which of course can't be in my version because it's a pure regex): tio.run/… \$\endgroup\$
    – Deadcode
    Commented Jan 27, 2019 at 11:03
5
\$\begingroup\$

C (gcc) / POSIX, 26 bytes

f(s){s=inet_pton(2,s,&s);}

Try it online!

Works as 64-bit code on TIO but probably requires that sizeof(int) == sizeof(char*) on other platforms.

\$\endgroup\$
2
  • \$\begingroup\$ @TobySpeight Yes, if you're on x86, you should probably try in 32-bit mode (-m32). \$\endgroup\$
    – nwellnhof
    Commented Oct 22, 2018 at 13:23
  • \$\begingroup\$ I got it to work, by passing s as a char* (no access to a ILP32 system here), and yes, I was mixing up with inet_aton(). \$\endgroup\$ Commented Oct 22, 2018 at 13:26
5
\$\begingroup\$

PHP 7+, 37 35 32 bytes

This uses the builtin function filter_var, to validate that it is an IPv4 address.

For it to work, you need to pass the key i over a GET request.

<?=filter_var($_GET[i],275,5**9);

Will output nothing (for a falsy result) or the IP (for a truthy result), depending on the result.

You can try this on: http://sandbox.onlinephpfunctions.com/code/639c22281ea3ba753cf7431281486d8e6e66f68e http://sandbox.onlinephpfunctions.com/code/ff6aaeb2b2d0e0ac43f48125de0549320bc071b4


This uses the following values directly:

  • 275 = FILTER_VALIDATE_IP
  • 1<<20 = 1048576 = FILTER_FLAG_IPV4
  • 5**9 = 1953125 (which has the required bit as "1", for 1048576)

Thank you to Benoit Esnard for this tip that saved me 1 byte!

Thank you to Titus for reminding me of the changes to the challenge.


I've looked into using the function ip2long, but it works with non-complete IP addresses.

Non-complete IPv4 addresses are considered invalid in this challenge.

If they were allowed, this would be the final code (only for PHP 5.2.10):

<?=ip2long($_GET[i]);

Currently, it isn't explicit in the documentation that this will stop working (when passed an incomplete ip) with newer PHP versions.

After testing, confirmed that that was the case.

Thanks to nwellnhof for the tip!

\$\endgroup\$
6
  • \$\begingroup\$ Using 5**9 instead of 1<<20 saves one byte here: PHP uses & to test the IPv4 / IPv6 flags, so any number between 1048576 and 2097151 is valid. \$\endgroup\$ Commented Oct 22, 2018 at 10:09
  • \$\begingroup\$ In newer PHP versions, ip2long doesn't allow incomplete addresses. \$\endgroup\$
    – nwellnhof
    Commented Oct 22, 2018 at 10:46
  • \$\begingroup\$ @BenoitEsnard Thank you! I've added it to the answer \$\endgroup\$ Commented Oct 22, 2018 at 11:50
  • \$\begingroup\$ @nwellnhof After testing, I confirm that that is the case. However, I don't think it is a good idea to use it, since it isn't explicitly documented. \$\endgroup\$ Commented Oct 22, 2018 at 11:51
  • \$\begingroup\$ +!! is not required; the OP now accepts arbitrary truthy values. \$\endgroup\$
    – Titus
    Commented Oct 23, 2018 at 12:44
5
\$\begingroup\$

C# (Visual C# Interactive Compiler), 84 79 65 bytes

s=>s.Split('.').Sum(t=>byte.TryParse(t,out var b)&t==b+""?1:5)==4

Try it online!

-5 and -14 bytes saved thanks to @dana!

# C# (Visual C# Interactive Compiler), 61 bytes

s=>s.Count(c=>c==46)==3&IPAddress.TryParse(s,out IPAddress i)

Try it online!

This is a work in progress. The code use System.Net (+17 bytes if you count it). if you wonder why I count and parse:

The limitation with IPAddress.TryParse method is that it verifies if a string could be converted to IP address, thus if it is supplied with a string value like "5", it consider it as "0.0.0.5".

source

As @milk said in comment, it will indeed fail on leading zeroes. So, the 61 bytes one is not working.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ @dana great. Nicely done! Four more and it will beat the 61 bytes solutions! \$\endgroup\$
    – aloisdg
    Commented Jan 29, 2019 at 17:17
4
\$\begingroup\$

Python 2, 85 82 81 bytes

-1 byte thanks to Kevin Cruijssen

from ipaddress import*
I=input()
try:r=I==str(IPv4Address(I))
except:r=0
print~~r

Try it online!

113 byte answer is deleted as it fails for 1.1.1.1e-80

\$\endgroup\$
4
  • 1
    \$\begingroup\$ You can golf print 1*r to print~~r. +1 though, since it seem to work for all possible test cases suggested thus far. PS: Your 113 byte answer fails for 1.1.1.1e-80. \$\endgroup\$ Commented Oct 22, 2018 at 10:52
  • \$\begingroup\$ @KevinCruijssen Thanks! Didn't think about such notation of numbers \$\endgroup\$ Commented Oct 22, 2018 at 11:11
  • \$\begingroup\$ Isn't ipaddress a Python 3 module? \$\endgroup\$
    – Farhan.K
    Commented Oct 24, 2018 at 12:55
  • \$\begingroup\$ @Farhan.K Dunno, but it works in TIO \$\endgroup\$ Commented Oct 24, 2018 at 13:51
4
\$\begingroup\$

Japt, 17 15 bytes

q.
ʶ4«Uk#ÿòs)Ê

Try it or run all test cases or verify additional test cases from challenge comments


Explanation

We split to an array on ., check that the length of that array is equal to 4 AND that the length when all elements in the range ["0","255"] are removed from it is falsey (0).

                 :Implicit input of string U
q.               :Split on "."
\n               :Reassign resulting array to U
Ê                :Length of U
 ¶4              :Equals 4?
   «             :&&!
    Uk           :Remove from U
      #ÿ         :  255
        ò        :  Range [0,255]
         s       :  Convert each to a string
          )      :End removal
           Ê     :Length of resulting array
\$\endgroup\$
2
  • \$\begingroup\$ Nice answer. Also verified for all suggested test cases thus far. Curious to see that explanation. \$\endgroup\$ Commented Oct 22, 2018 at 11:08
  • 2
    \$\begingroup\$ @KevinCruijssen, explanation added. Thanks for those additional test cases. \$\endgroup\$
    – Shaggy
    Commented Oct 22, 2018 at 11:09
4
\$\begingroup\$

ECMAScript pure regex, 41 bytes

^((2(?!5?[6-9])|1|(?!0\B))\d\d?\.?\b){4}$

Try it online!
Try it on regex101

I think the logic in this regex speaks for itself, so I will merely pretty-print but not comment it:

^
(
    (
        2(?!5?[6-9])
    |
        1
    |
        (?!0\B)
    )
    \d\d?
    \.?\b
){4}
$

This can be used to shave 2 bytes off the following other answers:

Some alternative 41 byte versions:

^((2(?!5?[6-9])|1|(?!0\d))\d\d?\.?\b){4}$
^(((2(?!5?[6-9])|1|(?!0))\d)?\d\.?\b){4}$
^(((2(?!5?[6-9])|1)\d|[1-9]?)\d\.?\b){4}$

Here is an alternative version that allows leading zeros, but does so consistently (octets may be represented by a maximum of 3 decimal digits):

^((2(?!5?[6-9])|1|0?)\d\d?\.?\b){4}$

Or allow any number of leading zeros:

^(0*(2(?!5?[6-9])|1?)\d\d?\.?\b){4}$

Or if allowed to have undefined behavior regarding leading zeros (as it so happens, a leading zero is only allowed only in 2-digit octets):

^((2(?!5?[6-9])|1?)\d\d?\.?\b){4}$

\$\endgroup\$
6
  • 1
    \$\begingroup\$ \b and \B... it's smart! \$\endgroup\$
    – mazzy
    Commented Jan 27, 2019 at 9:57
  • 1
    \$\begingroup\$ @mazzy Yes, those two really come in handy! I could've used (?!0\d) instead, but I like \B better! \$\endgroup\$
    – Deadcode
    Commented Jan 27, 2019 at 10:05
  • \$\begingroup\$ The powershell answer doesn't get shorter with your regexp. I'm sorry. Quotes are needed to convert an array to a string. Try it online! \$\endgroup\$
    – mazzy
    Commented Jan 27, 2019 at 10:35
  • 1
    \$\begingroup\$ The \.?\b saved me a byte on my answer too, thanks! \$\endgroup\$
    – Neil
    Commented Jan 27, 2019 at 21:34
  • 1
    \$\begingroup\$ Saved 3 bytes thx \$\endgroup\$
    – l4m2
    Commented Jan 28, 2019 at 20:35
3
\$\begingroup\$

Mathematica, 39 31 bytes

Original version:

¬FailureQ[Interpreter["IPAddress"][#]]&

Modified version (thanks to Misha Lavrov)

 AtomQ@*Interpreter["IPAddress"]

which returns True if the input is a valid IP address (try it).

In case you insist on getting 1 and 0 instead, then an additional 7 bytes would be necessary:

Boole/@AtomQ@*Interpreter["IPAddress"]
\$\endgroup\$
2
  • \$\begingroup\$ Since Interpreter["IPAddress"] returns a string for valid input, and some complicated failure object for invalid input, we can test for valid inputs with AtomQ[Interpreter["IPAddress"][#]]&, which can be further shortened to the function composition AtomQ@*Interpreter["IPAddress"]. Try it online! \$\endgroup\$ Commented Oct 22, 2018 at 17:45
  • \$\begingroup\$ Fails on an IPv6 address like 2001:0db8:85a3:0000:0000:8a2e:0370:7334. \$\endgroup\$
    – lirtosiast
    Commented Jan 27, 2019 at 1:58
3
\$\begingroup\$

JavaScript (ES6), 49 bytes

Returns a Boolean value.

s=>[0,1,2,3].map(i=>s.split`.`[i]&255).join`.`==s

Try it online!

\$\endgroup\$
3
\$\begingroup\$

Python 2, 93 89 67 53 bytes

[i==`int(i)&255`for i in input().split('.')]!=[1]*4>_

Try it online!

Thanks to Dennis for shaving another 14 bytes on the internal comparisons and exit code.

Special thanks to Jonathan Allan for shaving 22 bytes & a logic fix! Pesky try/except begone!

Taking properly formatted strings instead of raw bytes shaves off 4 bytes, thanks Jo King.

\$\endgroup\$
4
  • \$\begingroup\$ Your check can be golfed to i==`int(i)&255` . Also, you can force an error with [...]!=[1]*4>_, since you're using exit codes anyway. Try it online! \$\endgroup\$
    – Dennis
    Commented Oct 24, 2018 at 22:44
  • \$\begingroup\$ @Dennis I don't understand what >_ does. The bitwise and is quite ingenious though... I was unsuccessful in combining those myself. \$\endgroup\$ Commented Oct 24, 2018 at 22:58
  • 2
    \$\begingroup\$ If the != returns False, Python short-circuits and nothing happens; the interpreter exits normally. If it returns True, >_ raises a NameError, because the variable _ is undefined. \$\endgroup\$
    – Dennis
    Commented Oct 24, 2018 at 23:00
  • \$\begingroup\$ Figures I chain comparisons in my answer and then miss the obvious result in your comment. Thanks for the explanation. \$\endgroup\$ Commented Oct 24, 2018 at 23:13
3
\$\begingroup\$

sfk, 176 bytes

* was originally Bash + SFK but TIO has since added a proper SFK wrapper

xex -i "_[lstart][1.3 digits].[1.3 digits].[1.3 digits].[1.3 digits][lend]_[part2]\n[part4]\n[part6]\n[part8]_" +xed _[lstart]0[digit]_999_ +hex +linelen +filt -+1 -+2 +linelen

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ Would first checking the error printout from nc [addr] 1 -w1 shorten this? \$\endgroup\$
    – user77406
    Commented Oct 22, 2018 at 9:23
  • \$\begingroup\$ @Rogem nc accepts leading zeroes as well as IPv6 addresses, so I'd still have to handle those - and this is intended more as a sfk answer than a shell answer anyway. \$\endgroup\$
    – Οurous
    Commented Oct 22, 2018 at 9:30
3
\$\begingroup\$

Python3 Bash* 60

*Also other shells. Any one for which the truthy/falsy test passes on a program exit code

read I
python3 -c "from ipaddress import*;IPv4Address('$I')"

Explanation

The trouble with a pure Python solutions is that a program crashing is considered indeterminate. We could use a "lot" of code to convert an exception into a proper truthy/fasly value. However, at some point the Python interpreter handles this uncaught exception and returns a non-zero exit code. For the low-low cost of changing languages to your favourite Unix shell, we can save quite a bit of code!

Of course, this is vulnerable to injection attacks... Inputs such as 1.1.1.1'); print('Doing Something Evil are an unmitigated threat!

\$\endgroup\$
4
  • \$\begingroup\$ (Explanation it is (not Explaination).) \$\endgroup\$ Commented Oct 25, 2018 at 1:43
  • \$\begingroup\$ @PeterMortensen Yikes. It was even underlined in red. My browser tried to save me, but I wouldn't listen. Thanks for catching that! \$\endgroup\$
    – Sompom
    Commented Oct 25, 2018 at 14:50
  • \$\begingroup\$ Full programs are allowed to output via exit codes, therefore this could be 43 bytes. \$\endgroup\$ Commented Nov 5, 2018 at 16:29
  • \$\begingroup\$ @BMO Interesting. Thanks for pointing that out! I think the problem definiiton changed from "Truthy/Falsy" to also allowing arbitrary output since I posted this, but I could have just not noticed before :) \$\endgroup\$
    – Sompom
    Commented Nov 5, 2018 at 16:40
3
\$\begingroup\$

Bash, 15 bytes

ipcalc -c `cat`

Try it online!

Outputs exit code 0 for truthy, 1 for falsy.

\$\endgroup\$
1
  • \$\begingroup\$ The echo $(($?)) part is not needed since programs are allowed to output their result via exit code. \$\endgroup\$ Commented Nov 5, 2018 at 16:35
2
\$\begingroup\$

Red, 106 bytes

func[s][if error? try[t: load s][return off]if 4 <> length? t[return off]s =
form as-ipv4 t/1 t/2 t/3 t/4]

Try it online!

Returnd true or false

Explanation:

f: func [ s ] [
    if error? try [                  ; checks if the execution of the next block result in an error
        t: load s                    ; loading a string separated by '.' gives a tuple   
    ] [                              ; each part of which must be in the range 0..255
        return off                   ; if there's an error, return 'false' 
    ]
    if 4 <> length? t [              ; if the tuple doesn't have exactly 4 parts
        return off                   ; return 'false'  
    ]
    s = form as-ipv4 t/1 t/2 t/3 t/4 ; is the input equal to its parts converted to an IP adress
]
\$\endgroup\$
2
\$\begingroup\$

Stax, 14 bytes

∞n·Θ3ª&JH‼∙*~Γ

Run and debug it

Unpacked, ungolfed, and commented, it looks like this.

VB      constant 256
r       [0 .. 255]
'|*     coerce and string-join with "|"; i.e. "0|1|2|3 ... 254|255"
:{      parenthesize to "(0|1|2|3 ... 254|255)"
]4*     make 4-length array of number pattern
.\.*    string join with "\\."; this forms the complete regex
|Q      is the input a complete match for the regex?

Run this one

\$\endgroup\$
2
  • \$\begingroup\$ Surprised to know that you made the language Stax! it is working well. \$\endgroup\$
    – vrintle
    Commented Oct 22, 2018 at 17:14
  • \$\begingroup\$ Thanks! The space of golfing languages is surprisingly crowded, and I'm not sure if stax can justify its own existence on its merits, but my main goal was just to see if I could do it and maybe learn something. It ended up being more fun than expected. \$\endgroup\$
    – recursive
    Commented Oct 22, 2018 at 17:16
2
\$\begingroup\$

Python 3, 109 93 bytes

import re
lambda x:bool(re.match(r'^((25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(\.(?!$)|$)){4}$',x))

Explanation

Each octet can be 0 - 255 :

  • starts with 25 and having 0-5 as last digit
  • start with 2, has 0-4 as second digit and any digit at the end
  • starts with 1, and 00 - 99 as rest digits
  • has only 2 digits - 1-9 being the first one and any digit thereafter
  • or just a single digit

An octet can end with a (.) or just end, with the condition that it cannot do both , the negative lookahead (?!$) takes care of this case

Thanks @Zachary for making me realize I can discard spaces (since it is code golf)
Thanks @DLosc for the improvements and making me realize my mistake, its been corrected now.

\$\endgroup\$
4
  • 2
    \$\begingroup\$ Some explanation for this might help. \$\endgroup\$
    – Nissa
    Commented Oct 22, 2018 at 12:04
  • \$\begingroup\$ x: re.match=>x:re.match; , x => ,x, and ) is => )is should save 3 bytes. Also, in the regex, you can use \d for each occurrence of [0-9], and [1]=>1. This seems like a great first post, though! \$\endgroup\$
    – Adalynn
    Commented Oct 22, 2018 at 14:08
  • \$\begingroup\$ [1-9][0-9]|[0-9] can become [1-9]\d|\d (per Zacharý's advice), which can become [1-9]?\d. Also, instead of testing re.match(...)is not None, you can do bool(re.match(...)) since match objects are truthy and None is falsey. :) \$\endgroup\$
    – DLosc
    Commented Oct 22, 2018 at 18:05
  • \$\begingroup\$ Hmm. Actually, this fails on the test case 1.2.3.4.5 (and also 1.2.3.4., which isn't in the official list of test cases), because it can match a period instead of end-of-string after the fourth number. \$\endgroup\$
    – DLosc
    Commented Oct 22, 2018 at 18:23
2
\$\begingroup\$

Charcoal, 45 21 bytes

I∧⁼№θ.³¬Φ⪪θ.¬№E²⁵⁶Iλι

Try it online! Link is to verbose version of code. Edit: Saved 24 bytes by porting @Shaggy's Japt answer. Explanation:

    θ                   Input string
   №                    Count occurrences of
     .                  Literal `.`
  ⁼                     Equal to
      ³                 Literal 3
 ∧                      Logical And
       ¬                Logical Not
          θ             Input string
         ⪪              Split on
           .            Literal `.`
        Φ               Filter by
            ¬           Logical Not
               ²⁵⁶      Literal 256
              E         Map over implicit range
                   λ    Map value
                  I     Cast to string
             №          Count occurrences of
                    ι   Filter value
I                       Cast to string
                        Implicitly print
\$\endgroup\$
2
  • \$\begingroup\$ Fails for test cases with negative integers like 123.-50.0.12 or 1.1.1.-80. Everything else seems to work fine. So the <256 check should be in [0,255] instead. \$\endgroup\$ Commented Oct 22, 2018 at 9:55
  • \$\begingroup\$ @KevinCruijssen Actually the code to filter out invalid characters wasn't working because I forgot to change the variable in the inner loop. Should be fixed now. \$\endgroup\$
    – Neil
    Commented Oct 22, 2018 at 12:21
2
\$\begingroup\$

Retina, 46 44 bytes

^
.
^(\.(25[0-5]|(2[0-4]|1\d|[1-9])?\d)){4}$

Port of @OlivierGrégoire's Java answer, so make sure to upvote him!
-2 bytes thanks to @Neil.

Try it online.

Explanation:

^
.                           # Prepend a dot "." before the (implicit) input
^...$                       # Check if the entire string matches the following regex
                            # exactly, resulting in 1/0 as truthy/falsey:
 (                          #  Open a capture group
  \.                        #   A dot "."
    (25[0-5]                #   Followed by a number in the range [250,255]
    |(2[0-4]|         ) \d) #   or by a number in the range [200,249]
    |(      |1\d|     ) \d) #   or by a number in the range [100,199]
    |(          |[1-9]) \d) #   or by a number in the range [10,99]
    |(                )?\d) #   or by a number in the range [0,9]
 )                          #  Close capture group
  {4}                       #  This capture group should match 4 times after each other
\$\endgroup\$
2
  • \$\begingroup\$ My attempt (which I didn't post because the question got put on hold at the time) was the same length, but didn't have the \d group optimisation, so you can save two bytes because you don't need the M specification on the last line. \$\endgroup\$
    – Neil
    Commented Oct 23, 2018 at 0:41
  • \$\begingroup\$ I managed to get Retina down to 42 bytes by porting the Perl 6 answer but this answer also works in 0.8.2 which my port doesn't. \$\endgroup\$
    – Neil
    Commented Oct 23, 2018 at 1:13
2
\$\begingroup\$

Perl 5 -pF/\./, 47 bytes

$\=@F==4&&!/[^0-9.]/;$\&&=!/^0./&&$_<256for@F}{

Try it online!

\$\endgroup\$
0
2
\$\begingroup\$

Jelly, 11 bytes

⁹ḶṾ€ṗ4j€”.ċ

A monadic link accepting a list of characters which yields \$1\$ if it's a valid address and \$0\$ otherwise. Builds a list of all \$256^4=4294967296\$ addresses and then counts the number of occurrences of the input therein.

Here's similar @ Try it online! that uses \$16\$ () rather than \$256\$ (), since the method is so inefficient!

How?

⁹ḶṾ€ṗ4j€”.ċ - Link: list of characters, S
⁹           - literal 256
 Ḷ          - lowered range = [0,1,2,...,254,255]
  Ṿ€        - unevaluate €ach = ['0','1',...,['2','5','4'],['2','5','5']]
    ṗ4      - 4th Cartesian power = ALL 256^4 lists of 4 of them
            -               (e.g.: ['0',['2','5','5'],'9',['1','0']])
        ”.  - literal '.' character
      j€    - join for €ach (e.g. ['0','.','2','5','5','.','9','.','1','0'] = "0.255.9.10")
          ċ - count occurrences of right (S) in left (that big list)
\$\endgroup\$
1
  • \$\begingroup\$ Why does the version with 65,536 IPs take 1.8 seconds? o_O \$\endgroup\$
    – Dennis
    Commented Oct 24, 2018 at 14:41
2
\$\begingroup\$

Retina, 42 41 bytes

~(K`

255*
["^(("|'|]")\.?\b){4}$"L$`
$.`

Try it online! Based on a previous version of @nwellnhof's Perl 6 answer, but 1 byte saved by stealing the \.?\b trick from @Deadcode's answer. Explanation:

K`

Clear the work area.

255*

Insert 255 characters.

["^(("|'|]")\.?\b){4}$"L$`
$.`

Generate the range 0..255 separated with |s, prefixed with ^((, and suffixed with )\.?\b){4}$, thus building the regular expression ^((0|1|...255)\.?\b){4}$.

~(

Evaluate that on the original input.

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

Pip, 25 16 bytes

a~=X,256RL4J"\."

Takes the candidate IP address as a command-line argument. Try it online! or Verify all test cases

Explanation

Regex solution, essentially a port of recursive's Stax answer.

                  a is 1st cmdline arg (implicit)
    ,256          Range(256), i.e. [0 1 2 ... 255]
   X              To regex: creates a regex that matches any item from that list
                  i.e. essentially `(0|1|2|...|255)`
        RL4       Create a list with 4 copies of that regex
           J"\."  Join on this string
 ~=               Regex full-match
a                 against the input
\$\endgroup\$

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.