2

次のような単語のリストがあります。

l = """abca
bcab
aaba
cccc
cbac
babb
"""

最初と最後の文字が同じで、真ん中の 2 文字が最初と最後の文字と異なる単語を見つけたいです。

望ましい最終結果:

['abca', 'bcab', 'cbac']

私はこれを試しました:

re.findall('^(.)..\\1$', l, re.MULTILINE)

ただし、不要な単語もすべて返します。[^...] をどうにか使おうと思ったのですが、思いつきませんでした。セットでこれを行う方法があります (上記の検索結果をフィルタリングするため) が、私は正規表現を探しています。

出来ますか?

4

7 に答える 7

3

編集:ネガティブルックビハインドアサーションの代わりにネガティブルックアヘッドアサーションを使用するように修正されました。@AlanMooreと@bukzorの説明に対するコメントを読んでください。

>>> [s for s in l.splitlines() if re.search(r'^(.)(?!\1).(?!\1).\1$', s)]
['abca', 'bcab', 'cbac']

このソリューションでは、負の先読みアサーションを使用します。これは、「現在の位置の後に他の何かとの一致がない場合にのみ、現在の位置と一致する」ことを意味します。ここで、先読みアサーションを見てください- (?!\1)。これはすべて、「最初の文字が続かない場合にのみ、現在の文字と一致する」ことを意味します。

于 2012-05-01T19:45:04.383 に答える
3

これを行う方法はたくさんあります。おそらく最も簡単なものは次のとおりです。

re.findall(r'''
           \b          #The beginning of a word (a word boundary)
           ([a-z])     #One letter
           (?!\w*\1\B) #The rest of this word may not contain the starting letter except at the end of the word
           [a-z]*      #Any number of other letters
           \1          #The starting letter we captured in step 2
           \b          #The end of the word (another word boundary)
           ''', l, re.IGNORECASE | re.VERBOSE)

[a-z]必要に応じて、 に置き換えることで要件を少し緩めることができます\w。これにより、文字だけでなく数字とアンダースコアも許可されます。*パターンの最後を に変更して、4 文字の単語に制限することもできます{2}

また、私は Python にあまり詳しくないので、あなたの使用法findallが正しいと仮定しています。

于 2012-05-01T19:30:04.140 に答える
1

これが私がそれをする方法です:

result = re.findall(r"\b([a-z])(?:(?!\1)[a-z]){2}\1\b", subject)

これはジャスティンの答えに似ていますが、1回だけ先読みを行う場合、これは消費された各文字をチェックします。

\b
([a-z])  # Capture the first letter.
(?:
  (?!\1)   # Unless it's the same as the first letter...
  [a-z]    # ...consume another letter.
){2}
\1
\b

実際のデータがどのように見えるかわかりません[a-z]。サンプルデータで機能するため、任意に選択してください。同じ理由で、長さを4文字に制限しました。ジャスティンの答えと同様に、{2}*+または他の数量詞を変更することをお勧めします。

于 2012-05-01T21:33:25.597 に答える
1

正規表現と一体に。

[
    word
    for word in words.split('\n')
    if word[0] == word[-1]
    and word[0] not in word[1:-1]
]
于 2012-05-01T20:13:09.900 に答える
1

正規表現を使用する必要がありますか? これは、同じことを行うためのより Pythonic な方法です。

l = """abca
bcab
aaba
cccc
cbac
babb
"""

for word in l.split():
  if word[-1] == word[0] and word[0] not in word[1:-1]:
     print word
于 2012-05-01T21:10:34.740 に答える
0

これは、ネガティブ先読みまたは後読みアサーションを使用して行うことができます。詳細については、 http://docs.python.org/library/re.htmlを参照してください。

于 2012-05-01T19:22:08.787 に答える
0

Pythonの第一人者ではありませんが、これはおそらく

re.findall('^(.)(?:(?!\1).)*\1$', l, re.MULTILINE)

拡張 (複数行修飾子を使用):

^                # begin of line
  (.)            # capture grp 1, any char except newline
  (?:            # grouping
     (?!\1)         # Lookahead assertion, not what was in capture group 1 (backref to 1)
     .              # this is ok, grab any char except newline
  )*             # end grouping, do 0 or more times (could force length with {2} instead of *)
  \1             # backref to group 1, this character must be the same
$                # end of line
于 2012-05-01T21:52:28.440 に答える