当在Python中分割一个空string时,为什么split()返回空列表而split('\ n')返回?

我使用split('\n')获取一个string中的行,并发现''.split()返回一个空列表, [] ,而''.split('\n')返回[''] 。 有什么特别的原因造成这种差别吗?

有没有更方便的方法来计算string中的行数?

问题:我使用split('\ n')获取一个string中的行,并发现''.split()返回空列表[],而''.split('\ n')返回[''] 。

str.split()方法有两个algorithm。 如果没有提供任何参数,则会重复执行空格分割。 但是,如果给出了参数,则将其视为单个分隔符,不会重复运行。

在分割一个空string的情况下,第一个模式(无参数)将返回一个空列表,因为空白被吃掉,没有值放入结果列表。

相反,第二种模式(带有\n等参数)将产生第一个空白字段。 考虑如果你写了'\n'.split('\n') ,你会得到两个字段(一个分裂,给你两个半)。

问:这种差别有什么特别的原因吗?

当数据在具有可变数量的空白的列中alignment时,这第一种模式很有用。 例如:

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

第二种模式对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'] 

请注意,结果字段的数量比分隔符的数量多一个。 想想切一根绳子。 如果你没有削减,你有一块。 做一个切,给两块。 做两个裁员,给三件。 所以它是与Python的str.split(定界符)方法:

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

问题:还有更方便的方法来计算string中的行吗?

是的,有几个简单的方法。 一个使用str.count() ,另一个使用str.splitlines() 。 这两种方式将给出相同的答案,除非最后一行缺less\n 。 如果最后一个换行符丢失了, str.splitlines方法会给出准确的答案。 一个更准确的快速技术使用计数方法,然后纠正最后的换行符:

 >>> 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的问题:为什么heck是两种截然不同的algorithm,只能算作一个函数呢?

str.split的签名大约是20岁,那个时代的一些API是严格实用的。 虽然不完美,但方法签名也不“可怕”。 在绝大多数情况下,Guido的APIdeviseselect经受住了时间的考验。

目前的API并非没有优势。 考虑string,如:

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

当被要求将这些string分解为字段时,人们倾向于使用同一个英文单词“split”来描述这两个string。 当被要求阅读诸如fields = line.split()fields = line.split(',') ,人们倾向于将这些语句正确地解释为“将行拆分为字段”。

Microsoft Excel的文本到列的工具做了一个类似的APIselect,并在同一个工具合并两个分裂algorithm。 即使涉及多于一种algorithm,人们似乎在精神上将场分裂模型化为单个概念。

根据文件 ,这似乎只是它应该工作的方式:

用指定的分隔符分割空string会返回['']

如果没有指定sep或为None,则应用不同的分割algorithm:将连续空白的运行视为单个分隔符,并且如果string具有前导空格或尾随空格,则结果将在开始或结束处不包含空string。 因此,将空string或只包含空格的string拆分为无分隔符将返回[]。

因此,为了使它更清楚, split()函数实现了两种不同的分割algorithm,并使用参数的存在来决定运行哪一个。 这可能是因为它允许优化没有参数的参数比带参数的参数更多; 我不知道。

没有参数的.split()试图变得聪明。 它分割任何空格,制表符,空格,换行等,它也跳过所有空string的结果。

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

本质上,不带参数的.split()用于从string中提取单词,而不是用带参数的.split() ,而只需要一个string并将其分开。

这是差异的原因。

是的,分裂线不是一个有效的方法。 计算换行的数量,如果string不以换行符结束,则添加一行。

使用count()

 s = "Line 1\nLine2\nLine3" n_lines = s.count('\n') + 1 
 >>> 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. 

注意最后一句话。

要计算行数,你可以简单地计算有多less\n在那里:

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

最后一部分考虑到不以\n结尾的最后一行,即使这意味着Hello, World!Hello, World!\n有相同的行数(这对我来说是合理的),否则你可以简单地加1 \n的计数。

要计算行数,可以计算换行符的数量:

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

编辑

实际上,内置count 的其他答案更合适