web-dev-qa-db-ja.com

RegExは繰り返し文字に一致します

たとえば、私は文字列を持っています:

 aacbbbqq

結果として、私は次の試合をしたいと思っています:

 (aa, c, bbb, qq)  

私はこのようなものを書くことができることを知っています:

 ([a]+)|([b]+)|([c]+)|...  

しかし、私は醜く、より良い解決策を探していると思います。自己記述型の有限状態マシンではなく、正規表現のソリューションを探しています。

27
Andrew

次のものと一致させることができます:(\w)\1*

36
Qtax

itertools.groupbyはRexExpではありませんが、自己記述型でもありません。 :-) python docsからの引用:

# [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D
21
DrTyrsa

一般的に

秘訣は、必要な範囲の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 呼び出しを発行した場合、変更される可能性があります。

15
tzot

これは動作します。実際の例をこちらでご覧ください: http://www.rubular.com/r/ptdPuz0qDV

(\w)\1*
5
Rakesh Sankar

次のように後方参照をキャプチャすると、findallメソッドが機能します。

result = [match[1] + match[0] for match in re.findall(r"(.)(\1*)", string)]
2
SwiftsNamesake

以下を使用できます。

re.sub(r"(\w)\1*", r'\1', 'tessst')

出力は次のようになります。

'test'
1
Wesam Na