【问题标题】:Not allowing a specific string in an XSD Regular expression不允许 XSD 正则表达式中的特定字符串
【发布时间】:2019-12-14 16:21:54
【问题描述】:

我正在尝试使用正则表达式验证受限字符串...

<xs:simpleType name="myStringType">
    <xs:restriction base="xs:string">
        <xs:pattern value="^urn:mystuff:v1:(ABC\.(?!Acme).\S+\.\S+\.a\d+\.v\d+|ABC\.Acme\.\S+\.a\d+\.\d+\.\d+)$"/>
    </xs:restriction>
</xs:simpleType>

如您所见,我尝试使用的正则表达式是

^urn:mystuff:v1:(ABC\.(?!Acme).\S+\.\S+\.a\d+\.v\d+|ABC\.Acme\.\S+\.a\d+\.\d+\.\d+)$

我想验证以下内容:

urn:mystuff:v1:ABC.Test.MyData.a1.v1
urn:mystuff:v1:ABC.Acme.MyData.a1.0.1

但我希望以下失败

urn:mystuff:v1:ABC.Acme.MyData.a1.v1

这在online regex tester 中似乎可以正常工作,但是当我使用 Oxygen XML 编辑器时出现以下错误。

 Pattern value '^urn:mystuff:v1:(ABC\.(?!Acme).\S+\.\S+\.a\d+\.v\d+|ABC\.Acme\.\S+\.a\d+\.\d+\.\d+)$' is not a valid regular expression. The reported error was: 'This expression is not supported in the current option setting.'.

This post 建议 XSD 正则表达式不支持前瞻和后瞻,但问题与数字模式有关,因此在示例中采用了蛮力方法。这是可能的,因为可能性的子集非常有限。

当要禁止的值是特定字符串时,如何处理?

【问题讨论】:

  • 为了澄清一点,这个序列中的点(?!Acme).\S+ 是文字还是元字符?或者,这是一个不应该出现的错字吗?
  • 文字。示例如此模式
  • @x15 你删除了你的答案吗?
  • 这个与正则表达式有关的具体问题非常复杂。我什至不喜欢去想它,虽然我有很多次。我认为自己是专家。这个问题正好有解决办法。
  • 同意。其他问题有一些有用的花絮,但并没有真正为这个问题提供一个可行的答案,因为它有自己独特的挑战。

标签: regex xml xsd


【解决方案1】:

XSD 对它在正则表达式中接受的内容有一个特定的定义,并且它比许多其他正则表达式方言更具限制性。我认为设计者的意图是使用流行的正则表达式方言的“公共子集”,以便可以在任何平台上轻松实现。您正在使用此子集中未定义的 (?! ... )(?: ... ) 等结构。不幸的是,@x15 的答案也是如此。

告诉你为什么你的尝试不起作用很容易,找到一个可行的替代方案更难。我会选择一个简单的选择,即使用像test="matches($value, XX) or matches($value, YY) and not(matches($value, ZZ))" 这样的XSD 1.1 断言。使用纯 XSD 1.0 的解决方案可能是可行的,但我无法立即看到它。

【讨论】:

    【解决方案2】:

    附录:请注意,此解决方案在字符串中的固定位置植入伪断言。
    有关应该跨越整个字符串的断言的示例解决方案
    看到这个问题XML schema restriction pattern for not allowing specific string


    编辑:正如评论中指出的那样,如果这是唯一的,请使用 (..) 而不是 (?:..)
    支持的构造。
    变了!


    这个系列(?!Acme)\S+\.可以换成这个大系列:

    ([^A]\S*|A([^c.]\S*)?|Ac([^m.]\S*)?|Acm([^e.]\S*)?)\.

    它更大但应该涵盖所有情况并现在制作正则表达式:

    urn:mystuff:v1:(ABC\.([^A]\S*|A([^c.]\S*)?|Ac([^m.]\S*)?|Acm([^e.]\S*)?)\.\S+\.a\d+\.v\d+|ABC\.Acme\.\S+\.a\d+\.\d+\.\d+)
    

    https://regex101.com/r/qXv9HU/2

    展开

     urn:mystuff:v1:
     (                             # (1 start)
          ABC \. 
          (                             # (2 start)
               [^A]  \S* 
            |  A 
               ( [^c.] \S* )?                # (3)
            |  Ac 
               ( [^m.] \S* )?                # (4)
            |  Acm  
               ( [^e.] \S* )?                # (5)
          )                             # (2 end)
          \. 
          \S+ \. a \d+ \. v \d+ 
       |  
          ABC \. Acme \. \S+ \. a \d+ \. \d+ \. \d+ 
     )                             # (1 end)
    

    【讨论】:

    • 不幸的是,(?: ... ) 也在 XSD 正则表达式定义之外。
    【解决方案3】:

    最简单的方法是利用the XML Schem specification 中的这条规则:

    如果多个元素信息项作为&lt;simpleType&gt; 的子项出现,则应将这些值组合起来,就像它们作为单独的分支出现在单个正则表达式中一样。 注意:这是模式表示约束多个模式(第 4.3.4.3 节)和限制规则的结果,即在类型派生的同一步骤上指定的模式方面被 ORed 在一起,而在类型派生的不同步骤上指定的模式方面类型推导是 AND 在一起的。

    不要尝试使用单个正则表达式匹配两个允许的模式,而是指定两个单独的模式方面。如果需要第三种、第四种 URN 模式,这也会更自然地扩展。

    【讨论】:

    • 处理 AND 和 OR,但它不会立即提供一种执行 AND NOT 的方法。
    • 经过进一步思考,我相信我建议的方法适用于问题中描述的场景。字符串urn:mystuff:v1:ABC.Acme.MyData.a1.v1 将不匹配任何一个正则表达式,因此不需要'AND NOT'。除非我错过了什么。
    • 2 个正则表达式中的一个在某个位置使用了断言 (?!Acme),并且由于 unsupported 构造而出错。之所以需要 NOT,是因为不需要特定项目。所有这些条件都必须为真 ( urn:mystuff:v1:ABC\.\S+\.\S+\.a\d+\.v\d+ AND NOT urn:mystuff:v1:ABC\.Acme\S*\.\S+\.a\d+\.v\d+ ) OR ( urn:mystuff:v1:ABC\.Acme\.\S+\.a\d+\.\d+\.\d+ )
    猜你喜欢
    • 2017-08-15
    • 2015-10-06
    • 1970-01-01
    • 1970-01-01
    • 2011-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多