【问题标题】:string mask and offset with regex使用正则表达式的字符串掩码和偏移量
【发布时间】:2010-07-18 11:30:12
【问题描述】:

我有一个字符串,我尝试在其上创建一个正则表达式掩码,该掩码将显示N 的字数,给定一个偏移量。假设我有以下字符串:

"The quick, brown fox jumps over the lazy dog."

我想当时显示3个字:

偏移量0:"The quick, brown"
偏移量1:"quick, brown fox"
偏移量2:"brown fox jumps"
偏移量3: "fox jumps over"
偏移量4:"jumps over the"
偏移量5:"over the lazy"
偏移量6"the lazy dog."

我正在使用 Python,并且一直在使用以下简单的正则表达式来检测 3 个单词:

>>> import re
>>> s = "The quick, brown fox jumps over the lazy dog."
>>> re.search(r'(\w+\W*){3}', s).group()
'The quick, brown '

但我不知道如何使用一种掩码来显示接下来的 3 个单词而不是开头的单词。我需要保留标点符号。

【问题讨论】:

    标签: python regex regex-negation


    【解决方案1】:

    前缀匹配选项

    您可以通过使用可变前缀正则表达式跳过第一个 offset 单词并将单词三元组捕获到一个组中来完成这项工作。

    所以是这样的:

    import re
    s = "The quick, brown fox jumps over the lazy dog."
    
    print re.search(r'(?:\w+\W*){0}((?:\w+\W*){3})', s).group(1)
    # The quick, brown 
    print re.search(r'(?:\w+\W*){1}((?:\w+\W*){3})', s).group(1)
    # quick, brown fox      
    print re.search(r'(?:\w+\W*){2}((?:\w+\W*){3})', s).group(1)
    # brown fox jumps 
    

    我们来看看模式:

     _"word"_      _"word"_
    /        \    /        \
    (?:\w+\W*){2}((?:\w+\W*){3})
                 \_____________/
                    group 1
    

    这就是它所说的:匹配 2 单词,然后捕获到第 1 组,匹配 3 单词。

    (?:...) 构造用于对重复进行分组,但它们不是捕获的。

    参考文献


    注意“单词”模式

    应该说\w+\W*对于“单词”模式来说是一个糟糕的选择,如下例所示:

    import re
    s = "nothing"
    print re.search(r'(\w+\W*){3}', s).group()
    # nothing
    

    没有 3 个单词,但正则表达式无论如何都能匹配,因为 \W* 允许空字符串匹配。

    也许更好的模式是这样的:

    \w+(?:\W+|$)
    

    即,\w+ 后跟 \W+ 或字符串结尾 $


    捕获前瞻选项

    正如 Kobi 在评论中所建议的那样,此选项更简单,因为您只有一个静态模式。它使用findall 捕获所有匹配项(see on ideone.com):

    import re
    s = "The quick, brown fox jumps over the lazy dog."
    
    triplets = re.findall(r"\b(?=((?:\w+(?:\W+|$)){3}))", s)
    
    print triplets
    # ['The quick, brown ', 'quick, brown fox ', 'brown fox jumps ',
    #  'fox jumps over ', 'jumps over the ', 'over the lazy ', 'the lazy dog.']
    
    print triplets[3]
    # fox jumps over 
    

    它的工作原理是它匹配零宽度单词边界\b,使用前瞻捕获组 1 中的 3 个“单词”。

        ______lookahead______
       /      ___"word"__    \
      /      /           \    \
    \b(?=((?:\w+(?:\W+|$)){3}))
         \___________________/
               group 1
    

    参考文献

    【讨论】:

    • 另一个选项是\b(?=((?:\w+(?:\W+|$)){3})),如果你需要字符串中的所有三元组:rubular.com/r/ZncAfUZldv
    【解决方案2】:

    一种倾向是拆分字符串并选择切片:

    words = re.split(r"\s+", s)
    for i in range(len(words) - 2):
        print ' '.join(words[i:i+3])
    

    当然,这确实假设您在单词之间只有一个空格,或者不在乎是否所有空格序列都折叠成单个空格。

    【讨论】:

    • 我确实经历过,但我需要保持句子完整。
    【解决方案3】:

    不需要正则表达式

    >>> s = "The quick, brown fox jumps over the lazy dog."
    >>> for offset in range(7):
    ...     print 'offset {0}: "{1}"'.format(offset, ' '.join(s.split()[offset:][:3]))
    ... 
    offset 0: "The quick, brown"
    offset 1: "quick, brown fox"
    offset 2: "brown fox jumps"
    offset 3: "fox jumps over"
    offset 4: "jumps over the"
    offset 5: "over the lazy"
    offset 6: "the lazy dog."
    

    【讨论】:

      【解决方案4】:

      这里有两个正交问题:

      1. 如何拆分字符串。
      2. 如何构建由 3 个连续元素组成的组。

      对于 1,您可以使用正则表达式或 - 正如其他人指出的那样 - 一个简单的 str.split 就足够了。对于 2,请注意,您希望看起来与 itertools 的 配方中的 pairwise 抽象非常相似:

      http://docs.python.org/library/itertools.html#recipes

      所以我们编写了我们的广义 n-wise 函数:

      import itertools
      
      def nwise(iterable, n):
          """nwise(iter([1,2,3,4,5]), 3) -> (1,2,3), (2,3,4), (4,5,6)"""
          iterables = itertools.tee(iterable, n)
          slices = (itertools.islice(it, idx, None) for (idx, it) in enumerate(iterables))
          return itertools.izip(*slices)
      

      我们最终得到了一个简单的模块化代码:

      >>> s = "The quick, brown fox jumps over the lazy dog."
      >>> list(nwise(s.split(), 3))
      [('The', 'quick,', 'brown'), ('quick,', 'brown', 'fox'), ('brown', 'fox', 'jumps'), ('fox', 'jumps', 'over'), ('jumps', 'over', 'the'), ('over', 'the', 'lazy'), ('the', 'lazy', 'dog.')]
      

      或按您的要求:

      >>> # also: map(" ".join, nwise(s.split(), 3))
      >>> [" ".join(words) for words in nwise(s.split(), 3)]
      ['The quick, brown', 'quick, brown fox', 'brown fox jumps', 'fox jumps over', 'jumps over the', 'over the lazy', 'the lazy dog.']
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-10-16
        • 2019-08-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-10-01
        相关资源
        最近更新 更多