简体   繁体   中英

regex to match IP with mask in a jsonschema

There is a good solution here to match an IP with a mask eg 192.168.0.1/24 . I add the suggestion from https://regex101.com/ to escape the slash and it looks like this:

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

This definitely seems to work on regex101.

It needs to live inside a json file (jsonschema file) but seems to contain something illegal. Can't work out what it is, have looked at this , this , this and also tried using ujson instead of json (in python) as suggested here , but nothing works.

the following piece of jsonschema which contains that regex:

{
    "comment": "ipv4 with a mask",
    "data": {
        "network": {
        }
    },
    "schema": {
        "$schema": "http://json-schema.org/draft-04/schema#",
        "title": "ipv4 with a mask",
        "type": "object",
        "properties": {
            "subnet": {
                "title": "subnet",
                "type": "string",
                "pattern": "((^|\.)((25[0-5])|(2[0-4]\d)|(1\d\d)|([1-9]?\d))){4}\/(?:\d|[12]\d|3[01])$"
            }
        }
    }
}

...unfortunately won't even parse. Python is saying:

JSONDecodeError: Invalid \escape: line 16 column 33 (char 380)

I have been using the library fastjsonschema to check these things, but can't even parse the json and get that far.

Does anyone know how to fix this, somehow get that piece of regex to function in jsonschema?

For JSON, you need to escape each backslash \\ with another backslash:

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

So in the JSON schema, it would look like:

"pattern": "((^|\\.)((25[0-5])|(2[0-4]\\d)|(1\\d\\d)|([1-9]?\\d))){4}\\/(?:\\d|[12]\\d|3[01])$"

The regex you found (in the link) doesn't match well with digit grouping anyway. Try it with a few examples - the full match is correct but the groups returned include the dots with the numbers or just dots.

If you want all the parts of the IP address and not just a full match, then here's a regex based on this one . I've included matching for an optional subnet mask:

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

(remove the linebreaks which I've added for readability.) Demo here . Only the first 3 addrs should match, not the rest.

And if you only want the full match, and not the individual parts, then use this:

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

You won't believe it but 2 backslashes were not enough!

It does not work with 2 backslashes, it needs 3 or 4, so will go with 3. No need to give it more than it needs.

Had to spend a few more hours to realise this, but found this answer from @TimPietzcker which says:

You need to use escape the backslashes for the regex, and then escape them again for the string processor

So working code looks like this (tweaked the original schema slightly):

import json    
import fastjsonschema

schema = '''{
    "data": [{"subnet": "192.168.1.1/24"}],
        "$schema": "http://json-schema.org/draft-04/schema#",
        "type": "array",
        "items": {
            "type": "object",
            "properties": {
                "subnet": {
                    "title": "subnet",
                    "type": "string",
                    "pattern": "((^|\\\.)((25[0-5])|(2[0-4]\\\d)|(1\\\d\\\d)|([1-9]?\\\d))){4}\\\/(?:\\\d|[12]\\\d|3[01])$"
                }
            }
        }
    }''' 

schema = json.loads(schema)
validate = fastjsonschema.compile(schema)

def check_subnets(testcase):
    try: 
        validate([{"subnet": testcase}])
        print("yes a subnet")
    except fastjsonschema.JsonSchemaException:
        print("not a subnet")    

Then some tests:

>>> check_subnets("192.168.0.1/24") 
yes a subnet
>>> check_subnets("192.168.0.1/50")
not a subnet
>>> check_subnets("192.168.0.1")
not a subnet
>>> check_subnets("192.168.0.900/24")
not a subnet

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM