3

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 つの単語を表示する一種のマスクを作成する方法がわかりません。句読点を守らなければなりません。

4

4 に答える 4

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

\W*3 つの単語はありませんが、空の文字列の一致が許可されているため、正規表現はとにかく一致することができました。

おそらく、より良いパターンは次のようなものです。

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

つまり、 a の後に aまたは string の末尾\w+が続きます。\W+$


キャプチャ先読みオプション

コメントで Kobi が示唆しているように、静的パターンが 1 つしかないという点で、このオプションはより単純です。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、グループ 1 の 3 つの「単語」をキャプチャするために先読みを使用して、ゼロ幅の単語境界で一致することです。

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

参考文献

于 2010-07-18T11:48:01.957 に答える
2

1 つの傾斜は、文字列を分割してスライスを選択することです。

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

もちろん、これは、単語間に単一のスペースしかないか、すべての空白シーケンスが単一のスペースに折りたたまれていてもかまわないことを前提としています。

于 2010-07-18T11:37:19.033 に答える
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."
于 2010-07-18T13:27:06.983 に答える
1

ここには 2 つの直交する問題があります。

  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.']
于 2010-07-18T15:22:15.743 に答える