【问题标题】:Add exception to complicated regex向复杂的正则表达式添加异常
【发布时间】:2019-03-15 15:26:36
【问题描述】:

有一个非常复杂的正则表达式。

但我有一个问题。如果#++ 后面有字母,则删除它们。

问题:如何为(C++ 和 C# 标记)的当前正则表达式添加异常?

我使用了下一个正则表达式:

import re

text = 'Must-have skills: -.Net programming experience; -2 years experience in C++; C#/.Net, C++/.Net, C./.Net.'
text = re.sub(r'[!,.:;—](?= |$)', ' ', text)
print(re.sub(r'(?i)(?:(?!\.net\b|\b-\b)[^\w\s])+(?=[^\w\s]*\b)', ' ', text))

我得到了下一个结果:

'Must-have skills   .Net programming experience   2 years experience in C++  C .Net  C .Net  C .Net '

期望的结果:

'Must-have skills   .Net programming experience   2 years experience in C++  C# .Net  C++ .Net  C .Net '

当前正则表达式详细信息

  • (?i) - 不区分大小写模式开启
  • (?:(?!\.net\b|\b-\b)[^\w\s])+ - 任何标点符号 ([^\w\s]),尽可能多地出现 1 次或多次,但不启动任何序列:
    • \.net\b - .net 全文
    • | - 或
    • \b-\b - 用字符括起来的连字符
  • (?=[^\w\s]*\b) - 正向前瞻,需要 0+ 个标点字符,后面紧跟当前位置右侧的单词边界位置。

【问题讨论】:

    标签: python regex


    【解决方案1】:

    编辑

    #1

    与以下相同,但要短得多,我将定义必须在一组捕获的字符之前的字符

    >>> import re
    
    >>> text = 'Must-have skills: -.Net programming experience; -2 years experience in C++; C#/.Net, C++/.Net, C./.Net.'
    
    >>> re.sub('(?:(?<!\S)|(?<=[\s\+\.C#]))[\-!,.:;—/]|[\-!,.:;—/](?=\s|$)', ' ', text)
    
    
    #Output
    'Must-have skills   .Net programming experience   2 years experience in C++  C# .Net  C++ .Net  C  .Net '
    

    .

    说明

    • 这里的答案实际上与下面的答案相同,但不是声明必须在捕获的集合之前的字符,这些字符将被逐一处理,而是将它们全部定义在一个集合中。

    .

    #2

    一种非常肮脏的解决方案,但是

    稍后会发布解释;甚至可以改进它以提高可读性

    >>> import re
    
    >>> text = 'Must-have skills: -.Net programming experience; -2 years experience in C++; C#/.Net, C++/.Net, C./.Net.'
    
    >>> re.sub('(?:(?<!\S)|(?<=\s)|(?<=\+)|(?<=\.)|(?<=C)|(?<=#))[\-!,.:;—/]|[\-!,.:;—/](?=\s|$)', ' ', text)
    
    
    #Output
    'Must-have skills   .Net programming experience   2 years experience in C++  C# .Net  C++ .Net  C  .Net '
    

    .

    编辑:解释

    • 因此,使用(?: 打开时,我会说在这种情况下,我要捕获的查询应该在捕获集之前,该捕获集包含紧接在(?: 后面定义的任何内容。
    • 这里的关键是不能将以(?&lt;!(?&lt;= 开头的前瞻设置为忽略一系列值,所以我必须先以(?: 开头,然后给出多个(?&lt;! 和@ 987654329@ 表示捕获的内容应该或不应该在此字符之前,也不应在此其他字符之前,等等
    • 因此,使用(?: 打开后,我现在可以设置捕获的内容应该或不应该以
    • 开头的值
    • (?&lt;!\S) 开始,它确实是不需要的,但我将它包括在内,因为它会形成一个安全网。它基本上说范围 [\-!,.:;—/] 如果它前面有任何随机的非空白字符,则不应被捕获/执行
    • |(?&lt;=\s) 我是说 *OR [\-!,.:;—/] 如果前面有任何单个空白字符,则应该被捕获/执行
    • 对于|(?&lt;=\+)|(?&lt;=\.)|(?&lt;=C),我是说如果[\-!,.:;—/] 前面有+、. 或C,则应该捕获/执行它, 所以[\-!,.:;—/] 中的\. OR just . [a period] 将如果它前面有C 就像在你的字符串中一样被捕获/采取行动(记住(?&lt;=C));如果 + 前面有 ;[\-!,.:;—/] 中的 ;(请记住 (?&lt;=\+)),它将被捕获/执行。
    • | 之前的最后一个) 关闭了(?:
    • | 你知道是 OR,因为我不能把这个声明放在一个整体上,所以我必须重新定义 [\-!,.:;—/] 然后向前看,如果是,捕获/行动 [\-!,.:;—/]后跟空格或字符串结尾。 使用前瞻,您可以定义常规的单个字符串类型“范围”,因此您实际上可以在其中使用OR statements,但使用前瞻时不能使用

    【讨论】:

    • 令我印象深刻的是,您能够在同一条线上获得所有内容,并且我们在一分钟内相互发布。输出类似于我的,在行尾的“C .Net”之间有两个空格。
    • 我认为您的解决方案最终可能会更好。它的形式更真实,并且看起来更具可扩展性。我实际上没有看到我的额外空间,所以我会看看我是否可以提出更新。哈哈。我猜两者都适用于不同的场景。
    • @CT Hal,谢谢你的回答。这真的令人印象深刻。另外,我应该说空格的数量无关紧要。主要是处理标点符号。
    • @lemon,你想让我发布一个解释(这会很痛苦,但我会应要求提供),还是它的可读性足以不需要解释?
    • @FailSafe,那太好了!
    【解决方案2】:

    它与您的输出不太一样,但我能够通过颠倒两个 re.subs 的顺序并添加一个负面的后视来做到这一点,只有空白的差异。

    text = 'Must-have skills: -.Net programming experience; -2 years experience in C++; C#/.Net, C++/.Net, C./.Net.'
    text = re.sub(r'(?i)(?:(?!\.net\b|\b-\b)(?<!C)(?<!C\+)[^\w\s])+(?=[^\w\s]*\b)', ' ', text)
    text = re.sub('[!,.:;—](?= |$)', ' ', text)
    

    输出:

    print(text)
    Must-have skills   .Net programming experience   2 years experience in C++  C# .Net  C++ .Net  C  .Net 
    

    【讨论】:

      【解决方案3】:

      您可以通过在一个组中捕获您想要保留的内容并使用alternation 删除您不想要的内容来使用单个替换。

      这样,您可以使用要保留或要删除的案例来扩展模式。在替换中,您使用捕获组。除了使用内联修饰符(?i),您还可以在代码中使用re.IGNORECASE

      (c(?:\+{2}|#)|\.net\b)|[!,.:;/—]|-(?=[\d.])
      

      这将匹配:

      • (抓拍群
        • c(?:\+{2}|#)|\.net\b 匹配 c++ 或 c# 或 .net
      • )关闭捕获组
      • |或者
      • [!,.:;/—]匹配字符类中列出的任何字符
      • |或者
      • -(?=[\d.]) 匹配连字符,断言右边是数字或点

      Regex demo | Python demo

      例如

      import re
      regex = r"(c(?:\+{2}|#)|\.net\b)|[!,.:;/—]|-(?=[\d.])"
      text = 'Must-have skills: -.Net programming experience; -2 years experience in C++; C#/.Net, C++/.Net, C./.Net.'
      text = re.sub(regex, r"\1 ", text, 0, re.IGNORECASE)
      
      if text:
          print (text)
      
      # Must-have skills   .Net  programming experience   2 years experience in C++   C#  .Net   C++  .Net   C  .Net 
      

      【讨论】:

        猜你喜欢
        • 2012-07-10
        • 2019-04-21
        • 2022-07-20
        • 1970-01-01
        • 1970-01-01
        • 2015-02-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多