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

时间:2016-04-26 09:21:41

标签: regex xml date xsd escaping

我需要满足只接受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节有一个转义表。

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

谢谢!

2 个答案:

答案 0 :(得分: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可以简单地替换为/。也许它们是一些早期形式的正则表达式的回归,允许其他分隔符,但要求它们保持一致。

从你试图解决问题的方法来看,我觉得你对正则表达式没有透彻的理解。我担心要让这个工作,你将不得不咬紧牙关,了解它是如何工作的;调试复杂的正则表达式很困难,你不会通过反复试验来解决它。

答案 1 :(得分:1)

如果您检查XSD正则表达式语法resources,您会注意到不支持non-capturing groups(?:...)),也不支持backreferences\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})

请参阅this regex demo

注意acc。到regular-expressions.info

  

特别值得注意的是完全没有像插入符号和美元,单词边界和外观这样的锚点。 XML模式始终隐式地锚定整个正则表达式。正则表达式必须匹配元素的整个元素才能被认为是有效的。

所以,你不应该在XSD正则表达式中使用^(字符串的开头)和$(字符串的结尾)。

/符号在正则表达式中转义为正则表达式分隔符,而在XSD正则表达式中,没有正则表达式分隔符(因为唯一的操作是匹配< / em>,并且没有修饰符:XML schemas do not provide a way to specify matching modes)。因此,不要逃避XSD正则表达式中的/

在线测试注意

如果您在regex101.com或类似网站进行测试,请注意,在大多数情况下,如果选择/作为正则表达式分隔符,则需要转义\。完成测试后,您可以安全地删除/之前的 List<ResolveInfo> myList = getPackageManager().queryBroadcastReceivers(i,0);