たとえば、私は文字列を持っています:
aacbbbqq
結果として、私は次の試合をしたいと思っています:
(aa, c, bbb, qq)
私はこのようなものを書くことができることを知っています:
([a]+)|([b]+)|([c]+)|...
しかし、私は醜く、より良い解決策を探していると思います。自己記述型の有限状態マシンではなく、正規表現のソリューションを探しています。
次のものと一致させることができます:(\w)\1*
itertools.groupby
はRexExpではありませんが、自己記述型でもありません。 :-) python docsからの引用:
# [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D
秘訣は、必要な範囲の1つの文字に一致させてから、同じ文字のすべての繰り返しに一致することを確認することです。
>>> matcher= re.compile(r'(.)\1*')
これは、任意の1文字(.
)と一致し、その繰り返し(\1*
)があれば一致します。
入力文字列について、次のように目的の出力を取得できます。
>>> [match.group() for match in matcher.finditer('aacbbbqq')]
['aa', 'c', 'bbb', 'qq']
注:一致グループのため、re.findall
は正しく機能しません。
any文字に一致させたくない場合は、正規表現の.
を適宜変更します。
>>> matcher= re.compile(r'([a-z])\1*') # only lower case ASCII letters
>>> matcher= re.compile(r'(?i)([a-z])\1*') # only ASCII letters
>>> matcher= re.compile(r'(\w)\1*') # ASCII letters or digits or underscores
>>> matcher= re.compile(r'(?u)(\w)\1*') # against unicode values, any letter or digit known to Unicode, or underscore
後者をu'hello²²'
(Python 2.x)または'hello²²'
(Python 3.x)に対して確認します。
>>> text= u'hello=\xb2\xb2'
>>> print('\n'.join(match.group() for match in matcher.finditer(text)))
h
e
ll
o
²²
\w
非Unicode文字列/バイト配列に対して最初に locale.setlocale
呼び出しを発行した場合、変更される可能性があります。
これは動作します。実際の例をこちらでご覧ください: http://www.rubular.com/r/ptdPuz0qDV
(\w)\1*
次のように後方参照をキャプチャすると、findallメソッドが機能します。
result = [match[1] + match[0] for match in re.findall(r"(.)(\1*)", string)]
以下を使用できます。
re.sub(r"(\w)\1*", r'\1', 'tessst')
出力は次のようになります。
'test'