なんらかの正規表現を書いて、それを使ったfindall
か何かを使って一発必中で
['ABccABcccDE', 'ABcccDE', 'ABcccDEccccDE']
を得るのは難しいです。なので、こういうプログラムを書くことになるのではないかと思います。
python3
1import re
2
3body = 'ABccABcccDEccccDE'
4front = 'AB'
5rear = 'DE'
6
7front_indexes = [m.span() for m in re.finditer(front, body)] # => [(0, 2), (4, 6)]
8rear_indexes = [m.span() for m in re.finditer(rear, body)] # => [(9, 11), (15, 17)]
9
10pairs = [
11 (front_index, rear_index)
12 for front_index in front_indexes
13 for rear_index in rear_indexes
14 if 2 <= rear_index[0] - front_index[1] <= 10
15] # => [((0, 2), (9, 11)), ((4, 6), (9, 11)), ((4, 6), (15, 17))]
16
17result = [body[front_index[0]:rear_index[1]] for front_index, rear_index in pairs]
18
19print(result) # => ['ABccABcccDE', 'ABcccDE', 'ABcccDEccccDE']
20
追記
上記に挙げたコードは、何をやっているかが分かりやすいかもしれませんが、ちょっと芸がない気がしました。それで
- one-pass(所与の
body
の最初から最後まで走査するのを一回で済ませること)で、出来ないか?
- 無駄を省く何らかの最適化が出来ないか?
ということで以下のコードになりました。
python3
1# body = 'ABccABcccDEccccDE'
2body = 'AB123AB67890DExxDEyyyABzzDE##ABDE@@@@@DE' # 動作確認用
3front = 'AB'
4rear = 'DE'
5
6MIN_LENGTH = 2
7MAX_LENGTH = 10
8
9result = [] # 条件に該当した文字列を格納するリスト
10front_indexes = [] # front文字列の開始位置をappendしつつ、使わなくなったものは先頭からpop(0)で削除していくFIFOリスト
11
12# body を左から読み、front および rear の出現を処理するループ
13for i in range(len(body)):
14 if body[i:i+len(front)] == front:
15 front_indexes.append(i)
16 elif body[i:i+len(rear)] == rear:
17 for i_fr in [*front_indexes]:
18 s = body[i_fr + len(front):i] # AB と DE の間にある文字列
19 if len(s) <= MAX_LENGTH:
20 if MIN_LENGTH <= len(s):
21 result.append(s)
22 else: # len(s) が MAX_LENGTH を超えたので、このsを作ったi_frをfront_indexesから削除
23 front_indexes.pop(0)
24
25
26print(result)
27print(front_indexes)
28
出力結果:
['123AB67890', '67890', '67890DExx', 'zz', 'zzDE##AB', 'DE@@@@@']
[29]
基本的な流れは以下です。
body
を左端から右端まで読み、front
文字列が見つかったら、front_indexes
にその位置を追加します。
rear
文字列が見つかったら、front_indexes
に保持している、front
のインデクスを小さいほうから読み、front
とrear
に挟まれている部分文字列をs
として作ります。
s
の長さが要件を満たしていれば、該当文字列のリストに追加します。
s
の長さが要件の最大長を超えていれば、そのs
を作ったfront
インデクスは、以後、使われないので、front_indexes
から削除します。
上記の実行例では、front
文字列の出現箇所は、0, 5, 21, 29 の4箇所ですが、プログラムの実行中、front_indexes
の長さは最大2までにしかならず、プログラム終了時には最後の出現位置の 29 のみを含むリストになっています。
※いちおう良さげに動いてるっぽいですが、どこかバグっていたら、コメントからお知らせください。