[解決済み] Python の `string.split()` のジェネレータバージョンはありますか?
質問
string.split()
は
リスト
のインスタンスを返します。を返すバージョンはありますか?
ジェネレータ
で代用できますか?ジェネレータバージョンを持つことに反対する理由はありますか?
どのように解決するのですか?
高い確率で
re.finditer
はかなり最小限のメモリオーバーヘッドを使用します。
def split_iter(string):
return (x.group(0) for x in re.finditer(r"[A-Za-z']+", string))
デモです。
>>> list( split_iter("A programmer's RegEx test.") )
['A', "programmer's", 'RegEx', 'test']
を編集してください。
私のテスト方法が正しいと仮定して、python 3.2.1では一定のメモリを消費することを確認しました。私は非常に大きなサイズ(1GBかそこら)の文字列を作成し、その後、イテラブルを通して
for
ループで反復処理しました(リスト内包ではありません、余分なメモリが発生します)。これは、メモリの顕著な増加をもたらしませんでした (つまり、メモリの増加があったとしても、それは 1GB の文字列よりもはるかに少ないものでした)。
より一般的なバージョン。
コメントへの返答として "私は
str.split
との関連性が見出せないので、より一般的なものを紹介します。
def splitStr(string, sep="\s+"):
# warning: does not yet work if sep is a lookahead like `(?=b)`
if sep=='':
return (c for c in string)
else:
return (_.group(1) for _ in re.finditer(f'(?:^|{sep})((?:(?!{sep}).)*)', string))
# alternatively, more verbosely:
regex = f'(?:^|{sep})((?:(?!{sep}).)*)'
for match in re.finditer(regex, string):
fragment = match.group(1)
yield fragment
という考え方です。
((?!pat).)*
は、パターンがマッチし始めるだろうところまで貪欲にマッチすることを保証することによって、グループを「否定」します(ルークヘッドは正規表現の有限状態マシンの文字列を消費しません)。疑似コードでは、繰り返し消費される (
begin-of-string
xor
{sep}
) +
as much as possible until we would be able to begin again (or hit end of string)
デモです。
>>> splitStr('.......A...b...c....', sep='...')
<generator object splitStr.<locals>.<genexpr> at 0x7fe8530fb5e8>
>>> list(splitStr('A,b,c.', sep=','))
['A', 'b', 'c.']
>>> list(splitStr(',,A,b,c.,', sep=','))
['', '', 'A', 'b', 'c.', '']
>>> list(splitStr('.......A...b...c....', '\.\.\.'))
['', '', '.A', 'b', 'c', '.']
>>> list(splitStr(' A b c. '))
['', 'A', 'b', 'c.', '']
(注意すべきは
str.split
は醜い振る舞いをします。
sep=None
を最初に
str.strip
を実行して、先頭と末尾の空白を削除します。上記の例では意図的にそうしていません。最後の例で sep=
"\s+"
.)
(これを実装しようとすると、いろいろなバグ(内部的なre.errorを含む)に遭遇しました...。Negative lookbehindは固定長の区切り文字に制限されるので、それは使っていません。上記の正規表現以外のほとんどのものは、文字列の先頭と末尾のエッジケースでエラーになるようでした (例.
r'(.*?)($|,)'
で
',,,a,,b,c'
を返す
['', '', '', 'a', '', 'b', 'c', '']
を返し、最後に余計な空文字列が付きます。編集履歴を見れば、一見正しく見える正規表現に実は微妙なバグがあることがわかります)。
(もし、より高いパフォーマンスのためにこれを自分で実装したい場合、(heavweightではありますが、正規表現は最も重要なことはCで実行されます)、固定長のデリミタに対して以下の疑似コードで、いくつかのコードを書くでしょう(typesを使う?それでジェネレータを動かす方法はよく分からない?)。長さLの区切り文字をハッシュ化し、O(1)の更新時間で実行中のハッシュアルゴリズムを使って文字列をスキャンしながら、長さLの実行中のハッシュを維持する。ハッシュが区切り文字と等しくなる可能性がある場合、過去数文字が区切り文字であったかどうかを手動でチェックする。文字列の先頭と末尾の特殊なケース。これは、O(N)個のテキスト検索を行う教科書的アルゴリズムのジェネレータバージョンである。マルチプロセッシング版も可能である。これらはやりすぎに見えるかもしれませんが、この質問は、本当に巨大な文字列を扱っていることを暗示しています...。その時点で、バイト オフセットが少ない場合はキャッシュする、ディスク バックアップされたバイト文字列ビュー オブジェクトを使用してディスクから作業する、より多くの RAM を購入するなど、クレイジーなことを検討できるかもしれません。)
関連
-
python implement mysql add delete check change サンプルコード
-
[解決済み] Pythonには文字列の'contains'サブストリングメソッドがありますか?
-
[解決済み] Pythonで現在時刻を取得する方法
-
[解決済み] リストを均等な大きさの塊に分割するには?
-
[解決済み] Pythonで文字列の部分文字列を取得するにはどうすればよいですか?
-
[解決済み] Pythonで文字列を小文字にするには?
-
[解決済み] Pythonで標準エラー出力するには?
-
[解決済み] Pythonの「名前付きタプル」とは何ですか?
-
[解決済み】ネストされたディレクトリを安全に作成するには?
-
[解決済み】Pythonに三項条件演算子はありますか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
PicgoのイメージベッドツールをPythonで実装する
-
Pythonコードの可読性を向上させるツール「pycodestyle」の使い方を詳しく解説します
-
[解決済み】「RuntimeError: dictionary changed size during iteration」エラーを回避する方法とは?
-
[解決済み】ImportError: PILという名前のモジュールがない
-
[解決済み】TypeError: re.findall()でバイトのようなオブジェクトに文字列パターンを使用することはできません。)
-
[解決済み】TypeErrorを取得しました。エントリを持つ子テーブルの後に親テーブルを追加しようとすると、 __init__() missing 1 required positional argument: 'on_delete'
-
[解決済み】IndexError: invalid index to scalar variableを修正する方法
-
[解決済み】Flaskのテンプレートが見つからない【重複あり
-
[解決済み】ValueError: xとyは同じサイズでなければならない
-
[解決済み] 文字列の行を反復処理する