web-dev-qa-db-ja.com

Pythonで空の文字列を分割する場合、split( '\ n')が['']を返すのにsplit()が空のリストを返すのはなぜですか?

1つの文字列の行を取得するためにsplit('\n')を使用していますが、''.split()は空のリスト[]を返し、''.split('\n')['']を返します。そのような違いの特定の理由はありますか?

そして、文字列内の行をカウントするより便利な方法はありますか?

131
godice

質問:split( '\ n')を使用して1つの文字列の行を取得していますが、 ''。split()は空のリスト[]を返しますが、 ''。split( '\ n')は['']を返します。 。

str.split() メソッドには2つのアルゴリズムがあります。引数が指定されていない場合、空白の繰り返し実行で分割されます。ただし、引数が指定されている場合、繰り返し実行されることなく単一の区切り文字として扱われます。

空の文字列を分割する場合、最初のモード(引数なし)は空白が食べられ、結果リストに入れる値がないため、空のリストを返します。

対照的に、2番目のモード(\nなどの引数)は、最初の空のフィールドを生成します。 '\n'.split('\n')と書いた場合、2つのフィールド(1つの分割、2つの半分になります)を取得することを考慮してください。

質問:そのような違いの具体的な理由はありますか?

この最初のモードは、データが可変量の空白を含む列に配置される場合に役立ちます。例えば:

>>> data = '''\
Shasta      California     14,200
McKinley    Alaska         20,300
Fuji        Japan          12,400
'''
>>> for line in data.splitlines():
        print line.split()

['Shasta', 'California', '14,200']
['McKinley', 'Alaska', '20,300']
['Fuji', 'Japan', '12,400']

2番目のモードは、CSVなど、カンマが繰り返されて空のフィールドが示される区切りデータに役立ちます。例えば:

>>> data = '''\
Guido,BDFL,,Amsterdam
Barry,FLUFL,,USA
Tim,,,USA
'''
>>> for line in data.splitlines():
        print line.split(',')

['Guido', 'BDFL', '', 'Amsterdam']
['Barry', 'FLUFL', '', 'USA']
['Tim', '', '', 'USA']

結果フィールドの数は、区切り文字の数よりも1つ多いことに注意してください。ロープを切ることを考えてください。カットを行わない場合、1つのピースがあります。 1つのカットを行うと、2つのピースが得られます。 2つのカットを行うと、3つのピースが得られます。そして、それはPythonのstr.split(delimiter)メソッドの場合:

>>> ''.split(',')       # No cuts
['']
>>> ','.split(',')      # One cut
['', '']
>>> ',,'.split(',')     # Two cuts
['', '', '']

質問:そして、文字列の行を数えるより便利な方法はありますか?

はい、いくつかの簡単な方法があります。 1つは str.count() を使用し、もう1つは strを使用します.splitlines() 最終行に\nがない場合を除き、どちらの方法でも同じ答えが得られます。最後の改行がない場合、str.splitlinesアプローチは正確な答えを提供します。正確で高速な手法ではcountメソッドを使用しますが、最終的な改行に対して修正します。

>>> data = '''\
Line 1
Line 2
Line 3
Line 4'''

>>> data.count('\n')                               # Inaccurate
3
>>> len(data.splitlines())                         # Accurate, but slow
4
>>> data.count('\n') + (not data.endswith('\n'))   # Accurate and fast
4    

@Kazからの質問:なぜ、2つの非常に異なるアルゴリズムが単一の機能にシューホーン化されているのですか?

str.splitのシグネチャは約20年前のものであり、その時代のAPIの多くは厳密に実用的です。完全ではありませんが、メソッドのシグネチャも「ひどい」ものではありません。ほとんどの場合、GuidoのAPI設計の選択肢は時の試練に耐えてきました。

現在のAPIには利点があります。次のような文字列を検討してください。

ps_aux_header  = "USER               PID  %CPU %MEM      VSZ"
patient_header = "name,age,height,weight"

これらの文字列をフィールドに分割するように求められると、人々は両方を同じ英語の単語「分割」を使用して説明する傾向があります。 fields = line.split()fields = line.split(',')などのコードを読むように求められると、人々はステートメントを「行をフィールドに分割する」と正しく解釈する傾向があります。

Microsoft Excelの text-to-columnsツール は、同様のAPIを選択し、同じツールに両方の分割アルゴリズムを組み込んでいます。複数のアルゴリズムが関係している場合でも、人々はフィールド分割を単一の概念として精神的にモデル化しているようです。

214

ドキュメント によると、それは単に動作するはずの方法のようです

指定したセパレータで空の文字列を分割すると、['']が返されます。

Sepが指定されていない場合、またはNoneの場合、異なる分割アルゴリズムが適用されます:連続する空白の実行は単一のセパレーターと見なされ、文字列の先頭または末尾に空白がある場合、結果には開始または終了に空の文字列は含まれません。その結果、空の文字列または空白だけで構成される文字列をNone区切り文字で分割すると、[]が返されます。

そのため、より明確にするために、split()関数は2つの異なる分割アルゴリズムを実装し、引数の存在を使用してどちらを実行するかを決定します。これは、引数のないものよりも引数のないものを最適化できるためかもしれません。知りません。

28
unwind

パラメータなしの.split()は巧妙になります。空白、タブ、スペース、改行などで分割され、この結果としてすべての空の文字列もスキップされます。

>>> "  fii    fbar \n bopp ".split()
['fii', 'fbar', 'bopp']

基本的に、パラメータなしの.split()は、文字列から単語を抽出するために使用されますが、文字列を取得して分割するパラメータを持つ.split()とは異なります。

それが違いの理由です。

ええ、分割によって行を数えるのは効率的な方法ではありません。改行の数をカウントし、文字列が改行で終わらない場合は1つ追加します。

3
Lennart Regebro

count()を使用:

s = "Line 1\nLine2\nLine3"
n_lines = s.count('\n') + 1
2
Gareth Webber
>>> print str.split.__doc__
S.split([sep [,maxsplit]]) -> list of strings

Return a list of the words in the string S, using sep as the
delimiter string.  If maxsplit is given, at most maxsplit
splits are done. If sep is not specified or is None, any
whitespace string is a separator and empty strings are removed
from the result.

最後の文に注意してください。

行を数えるには、\nがいくつあるかを数えるだけです:

line_count = some_string.count('\n') + some_string[-1] != '\n'

最後の部分は、\nHello, World!の行数が同じであることを意味しますが、Hello, World!\nで終わっていない最後の行を考慮します(そうでない場合は合理的です) 1のカウントに\nを追加するだけです。

1
Bakuriu

行を数えるために、改行の数を数えることができます:

n_lines = sum(1 for s in the_string if s == "\n") + 1 # add 1 for last line

編集

他の答え ビルトインcountで、実際はより適切です

0
Jakub M.