如何在 XSD 架构中正确转义正则表达式模式?

问题描述 投票:0回答:2

我需要满足仅接受 MM/DD/YYYY 形式的值的要求。

根据我读到的内容:https://www.w3.org/TR/xmlschema11-2/#nt-dateRep 使用

<xs:simpleType name="DATE">
        <xs:restriction base="xs:date"/>
    </xs:simpleType>

不会工作,因为它的正则表达式显然不支持这种格式。

我找到并调整了这个格式:

^(?:(?:(?:0?[13578]|1[02])(\/)31)\1|(?:(?:0?[1,3-9]|1[0-2])(\/)(?:29|30)\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:0?2(\/)29\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:(?:0?[1-9])|(?:1[0-2]))(\/)(?:0?[1-9]|1\d|2[0-8])\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$

此表格:

\^\(\?:\(\?:\(\?:0\?\[13578\]\|1\[02\]\)\(\\/\)31\)\1\|\(\?:\(\?:0\?\[1,3-9\]\|1\[0-2\]\)\(\\/\)\(\?:29\|30\)\2\)\)\(\?:\(\?:1\[6-9\]\|\[2-9\]\d\)\?\d{2}\)$\|\^\(\?:0\?2\(\\/\)29\3\(\?:\(\?:\(\?:1\[6-9\]\|\[2-9\]\d\)\?\(\?:0\[48\]\|\[2468\]\[048\]\|\[13579\]\[26\]\)\|\(\?:\(\?:16\|\[2468\]\[048\]\|\[3579\]\[26\]\)00\)\)\)\)$\|\^\(\?:\(\?:0\?\[1-9\]\)\|\(\?:1\[0-2\]\)\)\(\\/\)\(\?:0\?\[1-9\]\|1\d\|2\[0-8\]\)\4\(\?:\(\?:1\[6-9\]\|\[2-9\]\d\)\?\d{2}\)$

现在我不再在 XML 编辑器中遇到无效的转义错误(使用 XML Spy),但我得到了这个:

invalid-escape: The given character escape is not recognized.

我已经根据这里的XML模式规范完成了转义: https://www.w3.org/TR/xmlschema-2/#regexs F.1.1 节有一个转义表。

任何人都可以帮忙解决这个问题吗?

谢谢!

regex xml date xsd escaping
2个回答
2
投票

如果您检查 XSD 正则表达式语法 resources,您会注意到不支持 非捕获组 (

(?:...)
),也不支持 反向引用
\n
之类要引用的实体)到使用捕获组捕获的文本,
(...)
)。

由于唯一的分隔符是

/
,因此您可以完全摆脱反向引用。

使用

((((0?[13578]|1[02])/31)/|((0?[13-9]|1[0-2])/(29|30)/))((1[6-9]|[2-9]\d)?\d{2}‌​)|(0?2/29/(((1[6-9]|[2-9]\d)?(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[35‌​79][26])00))))|(0?[1-9]|1[0-2])/(0?[1-9]|1\d|2[0-8])/(1[6-9]|[2-9]\d)?\d{2})

参见 这个正则表达式演示

请注意,根据。到正则表达式.info

特别值得注意的是完全没有锚点,例如脱字符号和美元、单词边界和环视。 XML 模式始终隐式锚定整个正则表达式。正则表达式必须匹配整个元素,该元素才被视为有效。

因此,您不应在 XSD 正则表达式中使用

^
(字符串开头)和
$
(字符串结尾)。

/
符号在正则表达式风格中被转义,它是正则表达式分隔符,而在XSD正则表达式中,没有正则表达式分隔符(因为唯一的操作是匹配,并且没有修饰符:XML模式)不提供指定匹配模式的方法)。因此,不要在 XSD 正则表达式
中转义 
/

在线测试仪测试注意

如果您在 regex101.com 或类似站点进行测试,请注意,在大多数情况下,如果选择

/
作为正则表达式分隔符,则需要对其进行转义。完成测试后,您可以在
\
之前安全地删除
/


1
投票

好的,所以你从这里开始(我将插入换行符以提高可读性):

    ^(?:(?:(?:0?[13578]|1[02])(\/)31)\1|(?:(?:0?[1,3-9]|1[0-2])(\/)
(?:29|30)\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$
|^(?:0?2(\/)29\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|
^(?:(?:0?[1-9])|(?:1[0-2]))(\/)(?:0?[1-9]|1\d|2[0-8])\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$

可怕的东西。现在,在 XSD 中:

(a) 没有

^
$
锚点,不需要它们(该模式是隐式锚定的)。所以把他们拿出来。您已通过将它们转义为
\^
\$
来回应,但这没有意义:您实际上并不希望在输入中使用扬抑符和美元符号。

(b) XSD 无法识别非捕获组

(?:xxxx)
。只需将它们替换为捕获组 - 也就是说,删除
?:
再次,您已经逃脱了问号,这根本没有任何意义。

(c)

\d
可能应该是
[0-9]
,除非您确实想要匹配非 ASCII 数字(例如泰语或东阿拉伯数字)

(d) 斜杠 (

/
) 不需要转义,也确实无法转义。因此,请将
\/
替换为
/

(e) 我看到一些反向引用,

\1
\2
\4
。 XSD 正则表达式不允许反向引用。但据我所知,这个正则表达式中的反向引用没有任何用处。它们中的大多数似乎都是对一组
(\/)
形式的反向引用,它只能匹配单个斜杠,因此反向引用
\1
可以简单地替换为
/
。也许它们是对某些早期形式的正则表达式的回归,允许替代分隔符但要求它们保持一致。

从您尝试解决这里的问题来看,在我看来您对正则表达式没有非常透彻的理解。我担心要让它发挥作用,你必须硬着头皮学习它是如何运作的;调试复杂的正则表达式很困难,并且您无法通过反复试验来获得正确的结果。

© www.soinside.com 2019 - 2024. All rights reserved.