不允许特定字符串

时间:2016-06-01 08:23:05

标签: xsd pattern-matching restriction lookahead

我需要编写一个对字段有限制的XSD架构,以确保这一点 该字段的值不包含任何位置的子字符串FILENAME。

例如,以下所有内容必须无效:

FILENAME
ORIGINFILENAME
FILENAMETEST
123FILENAME456

这些值都不应该有效。

在支持负向前瞻的正则表达式语言中,我可以通过编写/^((?!FILENAME).)*$来完成此操作,但XSD模式语言不支持负向前瞻。

如何实现与/^((?!FILENAME).)*$具有相同效果的XSD模式限制?

我需要使用模式,因为我无法访问XSD 1.1断言,这是另一个显而易见的可能性。

问题XSD restriction that negates a matching string涵盖了类似的情况,但在这种情况下禁止禁止字符串作为前缀,这使得检查约束更容易。如何扩展解决方案以涵盖我们必须检查输入字符串中的所有位置而不仅仅是开头的情况?

1 个答案:

答案 0 :(得分:2)

好的,OP已经说服我,虽然the other question mentioned有一个重叠的主题,但禁止字符串在所有位置被禁止,而不仅仅是作为前缀这一事实使事情变得复杂,需要一个单独的答案,至少对于XSD 1.0案例。 (我开始将这个答案添加为我对另一个问题的答案的附录,并且它变得太大了。)

这里可以使用两种方法。

首先,在XSD 1.1中 ,一个简单的形式

断言
not(matches($v, 'FILENAME'))

应该做这个工作。

其次,如果一个人被迫使用 XSD 1.0 处理器,则需要一个匹配所有且仅包含不包含禁用子字符串的字符串的模式(此处为'FILENAME')。

这样做的一种方法是确保字符“F”永远不会出现在输入中。这太激烈了,但确实有效:不包含禁用字符串的第一个字符的字符串不包含禁用字符串。

但是哪些字符串包含'F'的出现?它们很好,只要没有'F'后跟字符串'ILENAME'。

更抽象地说明最后一点,我们可以说任何可接受的字符串(任何不包含字符串'FILENAME'的字符串)都可以分为两部分:

  1. 不包含字符'F'
  2. 的前缀
  3. 出现零次或多次'F'后跟一个与'ILENAME'不匹配且不包含任何'F'的字符串。
  4. 前缀很容易匹配:[^F]*

    以F开头但与'FILENAME'不匹配的字符串有点复杂;正如我们不想取消所有'F'的出现一样,我们也不想取缔'FI','FIL'等等 - 但每次出现这种危险的字符串都必须遵循字符串的结尾,或者与禁止字符串的下一个字母不匹配的字母,或者是另一个'F',它开始我们需要测试的另一个区域。因此,对于禁用字符串的每个正确前缀,我们创建表单

    的正则表达式
    $prefix || '([^F' || next-character-in-forbidden-string || ']' 
        || '[^F]*'
    

    然后我们用or-bars加入所有正则表达式。

    在这种情况下的最终结果如下所示(我已经在这里和那里插入换行符,以便于阅读;在使用之前,它们将需要被取回):

    [^F]*
    ((F([^FI][^F]*)?)
    |(FI([^FL][^F]*)?)
    |(FIL([^FE][^F]*)?)
    |(FILE([^FN][^F]*)?)
    |(FILEN([^FA][^F]*)?)
    |(FILENA([^FM][^F]*)?)
    |(FILENAM([^FE][^F]*)?))*
    

    要记住两点:

    • XSD正则表达式是隐式锚定的;使用非锚定正则表达式求值程序对此进行测试将不会产生正确的结果。
    • 起初可能并不明显为什么选择中的替代选项都以[^F]*而不是.*结尾。考虑字符串'FEEFIFILENAME'可能有所帮助。我们必须检查每个出现的'F',以确保它后面没有'ILENAME'。