78105


find関数により、任意の文字列の頭のインデックスが求められます。

[code]

    str1 = "abcdefghijklmn"
    print(str1.find('cde'))
    #2
    
[/code]

では、同様に、任意の文字列が複数ある場合は、どのようにしたら良いのでしょう。  
よろしく、お願いいたします。

[code]

    str2 = "abcdefabcdeghicde"
    # 2,8,14
    
[/code]


CC BY-SA 4.0
2021-07-11T02:48:57.503
78103
2022-01-07T10:33:38.433
2021-07-11T03:18:31.170
3060
47148
question
python python3
find()関数、複数の文字列を扱うには？


いろいろな方法がありますが、正規表現を使って行う方法があります。

正規表現(reモジュール)の`finditer`メソッドを使ってMatchオブジェクトのイテレータを取得し、Matchオブジェクトのstartメソッドの返り値を見ればよいです。

[re --- 正規表現操作 — Python 3.9.4
ドキュメント](https://docs.python.org/ja/3/library/re.html#re.finditer)

[code]

    import re
    str2 = "abcdefabcdeghicde"
    res_iter = re.finditer("cde", str2) 
    res_list = [] #結果を入れるリスト
    for res in res_iter:
        res_list.append(res.start())
    
    print(res_list)
    
[/code]


CC BY-SA 4.0
2021-07-11T03:15:56.787
78105
2021-07-11T03:15:56.787
5246
78103
answer


以下は list comprehension + 文字列の比較です。

[code]

    str2 = 'abcdefabcdeghicde'
    query = 'cde'
    len_s, len_q = len(str2), len(query)
    result = [i for i in range(len_s-len_q+1) if query == str2[i:(i+len_q)]]
    print(result)
    # 実行結果
    [2, 8, 14]
    
[/code]

#### 余談

ところで、`re.finditer()` は正規表現による capture なので、単なる文字列(`fixed string`)での正規表現では部分文字列の
overlap を処理しません。

[code]

    import re
    
    str2 = 'xxx'
    query = 'xx'
    print([m.start() for m in re.finditer(query, str2)])
    # 実行結果
    [0]
    
    ##
    len_s, len_q = len(str2), len(query)
    result = [i for i in range(len_s-len_q+1) if query == str2[i:(i+len_q)]]
    print(result)
    # 実行結果
    [0, 1]
    
[/code]

overlap ありで capture したい場合には lookahead assertion を使います。

[code]

    import re
    
    str2 = 'xxx'
    query = r'(?=xx)'
    print([m.start() for m in re.finditer(query, str2)])
    # 実行結果
    [0, 1]
    
[/code]


CC BY-SA 4.0
2021-07-11T05:20:39.673
78107
2021-07-11T05:20:39.673
47127
78103
answer


このような関数を作りました。  
target_txtにはもともとの抽出前の文字列、find_txtにはtarget_txtから検索したい文字列を入れてください。そうすれば、検索したい文字列がどこから始まるかインデックスをリスト形式で返してくれます。

[code]

    def findallpos(target_txt : str, find_txt : str) :
        count = target_txt.count(find_txt)
    
        idx_list = []
        last_idx = -1
        for i in range(count):
            last_idx = last_idx + 1 + target_txt[last_idx + 1:].find(find_txt)
            idx_list.append(last_idx)
        return idx_list
    
[/code]

余談  
１００億文字のランダムなアルファベットのテキストファイルを作成し、その中に５個検索対象を紛れ込ませて検索をしたところ、For文を回すよりも格段に速い実行結果となりました。  
For文で行った場合は、１秒ほどかかったのに対し、この関数はほぼ一瞬で検索ができました。  
巨大な文字列からの検索の場合は、ぜひ使用してみてください。


CC BY-SA 4.0
2022-01-07T10:33:38.433
85547
2022-01-07T10:33:38.433
50791
78103
answer