使用正则表达式进行字符串掩码和偏移

3 投票
4 回答
5949 浏览
提问于 2025-04-16 01:28

我有一个字符串,想用正则表达式来显示指定数量的单词,给定一个偏移量。比如说,我有以下这个字符串:

"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个单词,而不是开头的那些。我需要保留标点符号。

4 个回答

1

不需要用正则表达式

>>> 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."
2

一种方法是把字符串分开,然后选择其中的一部分:

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

当然,这种方法假设你在单词之间只有一个空格,或者你不在乎所有的空白字符都被压缩成一个空格。

5

前缀匹配选项

你可以通过使用一个可变前缀的正则表达式来跳过前面 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 来捕获所有匹配项(查看 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 上匹配,使用前瞻来捕获 3 个“单词”到组 1 中。

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

参考资料

撰写回答