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


154

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

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


回答:


247

質問:1つの文字列の行を取得するためにsplit( '\ n')を使用していて、 ''。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
['', '', '']

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

はい、簡単な方法がいくつかあります。一つの用途はstr.count()および他の用途の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"

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

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


28

ドキュメントによるとそれは単にそれが機能するはずの方法であるようです:

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

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

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


4

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

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

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

それが違いの理由です。

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


2

使用count()

s = "Line 1\nLine2\nLine3"
n_lines = s.count('\n') + 1

4
+ 1は、テキストが「\ n」で終わっていない場合にのみ実行する必要があります。
Lennart Regebro 2013年

8
"\ n"で終わる場合、最後の行は空行です。役に立たないが、それでもラインとして数えられますね?
Jakub M.

2
番号。3行のテキストをファイルに書き込んで、それぞれに改行を付けると、ファイルに3行が含まれていると思います。UNIXでは、テキストファイルを常に改行で終了することをお勧めします。そうしないcat fileと、コマンドラインが文字化けし、Subversionが文句を言います。viは常に1を追加します。
user829755 2013年

2
>>> 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'

最後の部分は考慮に入れて終わらない最後の行を取り\n、この手段にもかかわらず、Hello, World!Hello, World!\n(私にとっては合理的である)同じ行数を持っている、そうでなければ、単に追加できる1のカウントに\n


0

行数を数えるには、改行の数を数えます:

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

編集

組み込みのもう1つの答えcountは、実際にはより適切です。


3
を使用するだけでなくcount、ブール値は追加可能です(実際、サブクラスですint)。そのため、genexpはとして記述できますsum(s == "\n" for s in the_string)
lvc 2013年

今、あなたは空の行だけを数えていますか?
Thijs van Dien

はい、空の行は破棄しません
Jakub M.
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.