【问题标题】:Combine a positive lookahead and negative lookahead?结合积极的前瞻和消极的前瞻?
【发布时间】:2012-02-20 20:06:38
【问题描述】:

我不擅长正则表达式,但我有以下内容,但我假设以下部分意味着查找 13 - 16 位数字,然后如果找到 3 - 4 位数字则返回成功。问题是 3 - 4 位数字是可选的,它们也可以在 13 - 16 位数字之前,所以我想我想结合一个积极的前瞻/后视,消极的前瞻/后视。这听起来有点复杂,有没有更简单的方法?

(\d{13,16})[<"'].*?(?=[>"']\d{3,4}[<"'])[>"'](\d{3,4})[<"']

这将匹配 ccnum 和以下 sn-p 中的系列:

<CreditCard> 
     name="John Doe""
     ccnum=""1111123412341231"" 
     series="339"
     exp="03/13">
</CreditCard>

但是,如果我删除 ccnum 或系列,它不会匹配任何内容,并且系列可以是可选的。该系列也可以出现在 ccnum 之前或之后,所以如果我将系列属性放在 ccnum 属性之前,它也不匹配任何东西。如果我在 ccnum 之前有一个系列作为单独的元素,例如或者如果我忽略系列元素,它也不匹配:

<CreditCard> 
<series>234</series>
<ccnum>1235583839293838</ccnum>
</CreditCard>

我需要正则表达式匹配以下场景,但我不知道元素的确切名称,在这种情况下,我只是将它们称为 ccnum 和 series。

以下是有效的:

<CreditCard> 
            <ccnum>1235583839293838</ccnum>
            <series>123</series>
</CreditCard>

<CreditCard ccnum="1838383838383833"> 
            <series>123</series>
</CreditCard>

<CreditCard ccnum="1838383838383833" series="139"
</CreditCard>

它还应该匹配以下内容,但不匹配:

<CreditCard ccnum="1838383838383833"
            </CreditCard>

<CreditCard series="139" ccnum="1838383838383833" 
            </CreditCard>

<CreditCard ccnum="1838383838383833"></CreditCard>

<CreditCard> 
    <series>123</series>                
    <ccnum>1235583839293838</ccnum>
</CreditCard>

<CreditCard>          
<ccnum series="123">1235583839293838</ccnum>
</CreditCard>

现在,为了让它工作,我正在使用 3 个单独的正则表达式:

1 以匹配安全码之前的信用卡号。

1 以匹配信用卡号之前的安全码。

1 仅匹配信用卡号。

我尝试将表达式组合成一个或,但我最终得到了 5 个组(前 2 个表达式中的 2 个和最后一个中的 1 个)

【问题讨论】:

  • \d{13,16} 有什么问题?
  • @leppie - 只匹配 ccnum,而不是可选的序列号
  • 那么你不应该为此使用正则表达式。只需使用 XML 解析器并使用正则表达式验证值。您甚至可以使用 XML Scheme 来验证值。
  • 元素和属性各不相同,所以我不会xml解析器。
  • the elements and attributes vary, so I can't an xml parser 是不合理的。你只是不会使用模式验证?使用 XmlReader 或仅使用常规 XPath 查询来定位文本节点并对其进行处理。或者考虑为您的语法编写一个完整的解析器(因为这就是它)

标签: c# .net regex regex-lookarounds


【解决方案1】:

使用 Parse 方法将 XML 拉入 XDocument 可能要容易得多。然后,您可以使用 XPath 或其他方法来查找该数据。

至于正则表达式:你的正则表达式对我来说太复杂了,但这是你如何使某个块成为可选的:“(thisisoptional)?”。

您无法解释这两个不同的订单,除非将两个订单手动包含到正则表达式中。因此,如果您希望能够匹配“ab”和“ba”(不同的顺序),则需要以下正则表达式:“((ab)|(ba))”。所以一切都在那里两次。您可以通过将“a”和“b”分别分解为一个字符串变量来减少这种讨厌的情况。

【讨论】:

  • 无法使用 xpath,因为 xml 不同。
【解决方案2】:

您可以尝试递归遍历 XML 文档并抓取与 ccnumseries 表达式匹配的每个属性和文本节点,并将它们附加到 List&lt;string&gt; ccNumListList&lt;string&gt; seriesList。如果ccnumseries 在DOM 树层次结构中的顺序相同,那么ccNumList[i] == seriesList[i]

进行递归树遍历的一个例子是here

【讨论】:

  • ccnum和series只是例子,它从xml到xml不同,所以我不能用xml解析器解析它。
  • @Xaisoft - 如果您只是针对 ccnumber 和系列的正则表达式检查每个文本节点和属性,那么元素和属性名称是什么并不重要。关键是因为数字将在文件中以相同的顺序出现(除非文件具有某种辅助 id,否则这是真的)两个列表应该以相同的顺序出现。
【解决方案3】:
(?<=[>\"'](\\d{3,4})[<\"'].{0,100})?[>\"'](\\d{13,16})[<\"'](?=.*[>\"'](\\d{3,4})[<\"'])?

这将创建三个捕获组,其中ccnum 始终位于第二个组中,series 可以位于第一个、第三个或任何组中。

ccnum = match.Groups[2].Value;
series = match.Groups[1].Value + m.Groups[3].Value;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多