【问题标题】:How do I match part of a string only if it is not preceded by certain characters?仅当字符串的一部分前面没有某些字符时,如何匹配它?
【发布时间】:2010-09-17 11:03:33
【问题描述】:

我创建了以下正则表达式模式,以尝试匹配以“PRI”或“SEC”结尾的长度为 6 个字符的字符串,除非字符串 =“SIGSEC”。例如,我想匹配 ABCPRI、XYZPRI、ABCSEC 和 XYZSEC,而不是 SIGSEC。

(\w{3}PRI$|[^SIG].*SEC$)

它非常接近并且有点工作(如果我传入“SINSEC”,它会返回“NSEC”的部分匹配),但我对它目前的形式感觉不太好。此外,我以后可能需要添加除“SIG”之外的更多排除项,并意识到这可能不会很好地扩展。有什么想法吗?

顺便说一句,我在 C# 中使用 System.Text.RegularExpressions.Regex.Match()

谢谢, 丰富

【问题讨论】:

    标签: c# .net regex negative-lookbehind


    【解决方案1】:

    假设您的正则表达式引擎支持负前瞻,试试这个:

    ((?!SIGSEC)\w{3}(?:SEC|PRI))
    

    编辑:一位评论者指出 .NET 确实支持负前瞻,所以这应该可以正常工作(感谢 Charlie)。

    【讨论】:

    • .NET 正则表达式确实支持负前瞻,所以这会起作用
    • 啊,很高兴知道,谢谢查理。我真的不是 .NET 人 ;)
    • 这很好用,丹,谢谢!运行一个快速测试,添加额外的排除匹配将是微不足道的。
    • 附带说明,.Net 正则表达式支持各种环视的无限长度环视。实际上 .Net 正则表达式和 JGsoft 引擎是唯一允许“在后向内查看完整正则表达式”的正则表达式引擎
    【解决方案2】:

    为了帮助分解 Dan 的(正确)答案,它的工作原理如下:

    (           // outer capturing group to bind everything
     (?!SIGSEC) // negative lookahead: a match only works if "SIGSEC" does not appear next
     \w{3}      // exactly three "word" characters
     (?:        // non-capturing group - we don't care which of the following things matched
       SEC|PRI  // either "SEC" or "PRI"
     )
    )
    

    一起:((?!SIGSEC)\w{3}(?:SEC|PRI))

    【讨论】:

      【解决方案3】:

      你可以试试这个:

      @"\w{3}(?:PRI|(?<!SIG)SEC)"
      
      • 匹配 3 个“单词”字符
      • 匹配 PRI 或 SEC(但不是在 SIG 之后,即排除 SIGSEC)(?

      另外,我可能需要添加更多内容 以后除“SIG”之外的排除和 意识到这可能无法扩展 太好了

      使用我的代码,您可以轻松添加其他异常,例如以下代码排除 SIGSEC 和 FOOSEC

      @"\w{3}(?:PRI|(?<!SIG|FOO)SEC)"
      

      【讨论】:

        【解决方案4】:

        为什么不使用更具可读性的代码?在我看来,这更易于维护。

        private Boolean HasValidEnding(String input)
        {
            if (input.EndsWith("SEC",StringComparison.Ordinal) || input.EndsWith("PRI",StringComparison.Ordinal))
            {
                if (!input.Equals("SIGSEC",StringComparison.Ordinal))
                {
                    return true;
                }
            }
            return false;
        }
        

        或一行

        private Boolean HasValidEnding(String input)
        {
            return (input.EndsWith("SEC",StringComparison.Ordinal) || input.EndsWith("PRI",StringComparison.Ordinal)) && !input.Equals("SIGSEC",StringComparison.Ordinal);
        }
        

        不是我不使用正则表达式,而是在这种情况下我不会使用它们。

        【讨论】:

        • 是的,我实际上是从完全按照这些思路开始的,但需求发生了变化,我决定将逻辑外部化。我选择在配置文件中使用正则表达式,以便在需要添加新的排除字符串时不必更改代码。
        【解决方案5】:

        就个人而言,我倾向于使用第二个变量来构建排除列表,然后将其包含到完整的表达式中 - 这是我过去在构建时使用的方法 any em> 复杂的表达式。

        类似exclude = 'someexpression'; prefix = 'list of prefixes'; suffix = 'list of suffixes'; expression = '{prefix}{exclude}{suffix}';

        【讨论】:

          【解决方案6】:

          您甚至可能不想在正则表达式中进行排除。例如,如果这是 Perl(我不懂 C#,但你可能可以跟着学),我会这样做

          if ( ( $str =~ /^\w{3}(?:PRI|SEC)$/ ) && ( $str ne 'SIGSEC' ) )
          

          要清楚。它正在做你想做的事:

          • 三个单词字符,后跟 PRI 或 SEC,以及
          • 这不是 SIGSEC

          没有人说你必须把所有东西都强加到一个正则表达式中。

          【讨论】:

          • 我同意,这可能是最明智的做法。然而,看起来他正在尝试使用正则表达式从文本中提取这些内容 - 不必担心处理您不想要的匹配项可能会导致更简洁的解决方案。
          猜你喜欢
          • 2017-08-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-09-27
          • 1970-01-01
          • 1970-01-01
          • 2022-06-21
          相关资源
          最近更新 更多