Ray*_*ger 218
问题:我使用split('\n')来获取一个字符串中的行,并发现'.split()返回空列表[],而'.split('\n')返回[''] .
所述str.split()方法有两种算法.如果没有给出参数,它会在重复的空格运行时分裂.但是,如果给出了参数,则将其视为单个分隔符,不会重复运行.
在拆分空字符串的情况下,第一个模式(无参数)将返回一个空列表,因为空格是被吃掉的,并且没有值放在结果列表中.
相反,第二种模式(带有诸如的参数\n)将产生第一个空字段.考虑一下你是否写过'\n'.split('\n'),你会得到两个字段(一个分割,给你两个半).
问题:这种差异有什么具体原因吗?
当数据在具有可变数量的空格的列中对齐时,第一种模式很有用.例如:
>>> 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']
Run Code Online (Sandbox Code Playgroud)
第二种模式对于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']
Run Code Online (Sandbox Code Playgroud)
注意,结果字段的数量比分隔符的数量大1.想想切割一根绳子.如果你没有削减,你就有一件.做一个切,给两件.做两次切割,给出三件.所以它是Python的str.split(分隔符)方法:
>>> ''.split(',') # No cuts
['']
>>> ','.split(',') # One cut
['', '']
>>> ',,'.split(',') # Two cuts
['', '', '']
Run Code Online (Sandbox Code Playgroud)
问题:是否有更方便的方法来计算字符串中的行?
是的,有几种简单的方法.一个使用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
Run Code Online (Sandbox Code Playgroud)
来自@Kaz的问题:为什么这两种截然不同的算法只能用于单一功能?
str.split的签名大约有20年的历史,那个时代的许多API都是严格务实的.虽然不完美,但方法签名也不是"可怕的".在大多数情况下,Guido的API设计选择经得起时间的考验.
当前的API并非没有优势.考虑字符串,例如:
ps_aux_header = "USER PID %CPU %MEM VSZ"
patient_header = "name,age,height,weight"
Run Code Online (Sandbox Code Playgroud)
当被要求将这些字符串分解为字段时,人们倾向于使用相同的英语单词"split"来描述.当被要求阅读诸如fields = line.split()
或之类的代码时fields = line.split(','),人们倾向于正确地将语句解释为"将一行划分为字段".
Microsoft Excel的文本到列工具提供了类似的API选择,并在同一工具中包含了两种拆分算法.尽管涉及多个算法,但人们似乎在精神上将场分裂建模为单一概念.
.split()没有参数试图变得聪明。它在任何空格、制表符、空格、换行符等上进行拆分,因此它还会跳过所有空字符串。
>>> " fii fbar \n bopp ".split()
['fii', 'fbar', 'bopp']
Run Code Online (Sandbox Code Playgroud)
本质上,.split()不带参数用于从字符串中提取单词,而不是.split()带参数,它只需要一个字符串并将其拆分。
这就是差异的原因。
是的,通过拆分来计算行数并不是一种有效的方法。计算换行次数,如果字符串不以换行结束,则加一个。
对于那些真正想要避免['']调用空字符串时返回这种默认行为的人split,这里有两种可能的单行解决方案:
list_ = s.split(*list(sep if s.count(sep) else []))
# Or this
list_ = s.split(sep) if s != "" else []
Run Code Online (Sandbox Code Playgroud)
以下是如何在实际示例中使用第一个:
import os
sep = os.linesep # Split char
s_empty = ""
empty = s_empty.split(*list(sep if s_empty.count(sep) else []))
s_nonempty = f"a{sep}b"
nonempty = s_nonempty.split(*list(sep if s_nonempty.count(sep) else []))
print(f"Empty string: {empty}, non-empty string: {nonempty}")
Run Code Online (Sandbox Code Playgroud)