正则表达式将 IP 与 jsonschema 中的掩码匹配

regex to match IP with mask in a jsonschema

有一个很好的解决方案here to match an IP with a mask eg 192.168.0.1/24. I add the suggestion from https://regex101.com/来转义斜杠,它看起来像这样:

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

这似乎绝对适用于 regex101。

它需要存在于 json 文件(json 架构文件)中,但似乎包含一些非法内容。无法弄清楚它是什么,已查看 , this, this and also tried using ujson instead of json (in python) as suggested here,但没有任何效果。

以下 json 包含该正则表达式的架构:

{
    "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])$"
            }
        }
    }
}

...不幸的是甚至不会解析。 Python 是说:

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

我一直在使用库 fastjsonschema 来检查这些东西,但甚至无法解析 json 并做到这一点。

有谁知道如何解决这个问题,以某种方式让那段正则表达式在 jsonschema 中运行?

对于 JSON,您需要使用另一个反斜杠转义每个反斜杠 \

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

所以在 JSON 架构中,它看起来像:

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

您找到的正则表达式(在 link 中)与数​​字分组无论如何都不匹配。尝试使用几个示例 - 完全匹配 是正确的,但返回的 groups 包括带有数字的点或仅包含点。

如果您想要 IP 地址的所有部分而不仅仅是完全匹配,那么这里是一个正则表达式 based on this one。我已经包括了对可选子网掩码的匹配:

^(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]))?$

(删除我为便于阅读而添加的换行符。)Demo here。只有前 3 个地址应该匹配,其余的不匹配。

如果你只想要完整的比赛,而不是个别的部分,那么使用这个:

^(?:(?: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]))?$

你不会相信,但 2 个反斜杠还不够!

它不适用于 2 个反斜杠,它需要 3 个或 4 个,所以将使用 3 个。 不需要给它比它需要的更多。

不得不多花几个小时才意识到这一点,但从@TimPietzcker 那里找到了 this answer,上面写着:

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

所以工作代码看起来像这样(稍微调整了原始模式):

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")    

然后是一些测试:

>>> 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