为什么在split()结果中返回空字符串?


120

什么是点'/segment/segment/'.split('/')回来['', 'segment', 'segment', '']

注意空元素。如果您要分割的分隔符恰好位于字符串的第一位置,并且位于字符串的末尾,那么它又能为您带来什么额外的价值呢?


1
我有同样的问题,并搜索了很长时间。现在,我了解到空结果确实很重要。感谢您的提问。
emeraldhieu 2011年

2
一个解决方案是strip()在分割之前使用从字符串中'/segment/segment/'.strip('/').split('/')
去除开头

Answers:


178

str.splitstr.join,所以

"/".join(['', 'segment', 'segment', ''])

让您返回原始字符串。

如果没有空字符串,则第一个和最后一个字符串'/'将丢失join()


11
很简单,但是可以完全回答问题。
orokusaki 2010年

我很震惊地发现卷曲引号实际上在Python中是有效的...但是,但是...如何?该文档似乎没有提到这一点。
蒂姆·皮茨克

@Tim,我不知道这些引号是怎么来的:/
John La Rooy 2012年

7
那么,您不是将Microsoft Word用作Python IDE吗?:)
蒂姆·皮茨克

1
@ aaa90210谁说简单的答案不是最好的?这是评论(首先是5年前),关于答案如何简单,但完全回答了问题。在句子中使用“ but”并不表示任何不好的意思。一个不简单的答案可能是一个更完整的答案(例如,包括与所提到的功能相关的相关决策或PEP)。
orokusaki

88

更一般而言,要删除split()结果中返回的空字符串,您可能需要查看该filter函数。

例:

filter(None, '/segment/segment/'.split('/'))

退货

['segment', 'segment']

3
谢谢你,我不知道为什么这个答案如此之遥,其他一切都是基本的东西。

6
如果希望将结果收集在列表中而不是将过滤器对象作为输出,请将整个过滤器结构放在中list(...)
TimVisée'17

29

这里有两点要考虑:

  • 期望结果'/segment/segment/'.split('/')['segment', 'segment']于是合理的,但这会丢失信息。如果split()按照您想要的方式工作,如果我告诉您a.split('/') == ['segment', 'segment'],您将无法告诉我是什么a
  • 结果应该是什么'a//b'.split()['a', 'b']?或['a', '', 'b']?即,是否应split()合并相邻的定界符?如果需要,那么将很难解析由字符分隔的数据,并且某些字段可以为空。我可以肯定,有很多人确实想要上述情况的结果中的空值!

最后,归结为两点:

一致性:如果我有n定界符,则在中a,我会在n+1返回值split()

应该可以做复杂的事情,并且可以轻松地做简单的事情:如果由于想要忽略空字符串split(),可以始终这样做:

def mysplit(s, delim=None):
    return [x for x in s.split(delim) if x]

但是如果不想忽略空值,则应该可以。

该语言必须选择一种定义split()-有太多不同的用例无法满足所有人的默认要求。我认为Python的选择是不错的选择,也是最合乎逻辑的选择。(顺便说一句,我不喜欢C的原因之一strtok()是因为它合并了相邻的定界符,因此很难对其进行认真的解析/标记化处理。)

有一个例外:a.split()没有参数会挤压连续的空格,但是有人可以认为在这种情况下这样做是正确的。如果您不想要这种行为,则可以始终这样做a.split(' ')


对于那些想知道重复空格,然后拆分,还是只使用非空字符串拆分的更快,我得到的是:python3 -m timeit "import re ; re.sub(' +', ' foo bar baz ', '').split(' ')"->每个循环875纳秒;python3 -m timeit "[token for token in ' foo bar baz '.split(' ') if token]"->每个循环616 ns
s3cur3,19年

8

x.split(y)始终返回列表1 + x.count(y)项是一种珍贵的规律性-为@ gnibbler本已指出,这让splitjoin对方的确切逆(因为它们显然应该是),这也正是各种分隔符连记录的语义(映射例如csv文件行[[引用网络的净额]],/etc/groupUnix中的行等等),它允许(如@Roman的回答所述)轻松检查(例如)绝对路径与相对路径(在文件路径和URL中),等等。

另一种看待它的方式是,您不应该肆意地将信息扔出窗外,以免获得任何好处。x.split(y)等于会得到什么x.strip(y).split(y)?没事,当然-它很容易使用第二种形式时,这就是你的意思,但如果第一种形式是任意视为指第二个,你有很多工作要做,当你希望第一个(如上一段所指出的,这绝非罕见。

但是实际上,根据数学规律进行思考是您可以自学的设计可传递API的最简单,最通用的方法。举一个不同的例子,对于任何有效的xy x == x[:y] + x[y:]-这立即表明为什么应该排除切片的一个极端非常重要。您可以表述不变的断言越简单,就越有可能产生的语义就是您在现实生活中需要的语义-这是神秘的事实,即数学在处理宇宙中非常有用。

尝试为split前导和尾随定界符是特殊情况的方言制定不变式...反例:像这样的字符串方法isspace并不是最大程度的简单- x.isspace()等效于x and all(c in string.whitespace for c in x)-愚蠢的前导x and是您经常发现自己编码的原因not x or x.isspace(),返回到应该is...字符串方法中设计的简单性(因此,空字符串“就是”您想要的任何东西)与街上人马的感觉相反,也许[[空集,如零&c,始终使大多数人感到困惑;-)]],但完全符合明显完善的数学常识!-)。


5

我不确定您要寻找哪种答案?您得到三个匹配,因为您有三个定界符。如果您不想要那个空的,只需使用:

'/segment/segment/'.strip('/').split('/')

4
-1是因为您得到四场比赛而不是三场比赛,这也并不能真正回答问题。
罗马

1
+1抵消了负面影响。.他没有说您会得到3个结果。他说“三个匹配项”代表“三个匹配项”,这在我看来是合乎逻辑的。但是,您不会获得任何“四次匹配”。不过,您的结果中确实会返回“四个元素”。而且,它并没有直接回答“为什么”,但是确实提供了一种简单的方法来获得他真正想要的东西……我认为这不应该被否决。如果您要挑剔某人(票数不菲,请多加注意),请多加注意!干杯! 8 ^)
kodybrown 2013年

@wasatchwizard感谢您的澄清。我感谢改正和建议。不幸的是,现在我的投票已锁定,无法更改。
2014年

我爱您的解决方案-剥离然后拆分以消除空洞的结果
Nam G VU

5

好吧,它让您知道那里有一个定界符。因此,看到4个结果会让您知道您有3个定界符。这使您能够使用此信息执行任何所需的操作,而不是让Python删除空元素,然后让您手动检查是否需要定界符(如果需要)。

一个简单的例子:假设您要检查绝对文件名和相对文件名。这样,您就可以使用拆分完成所有操作,而不必检查文件名的第一个字符是什么。


1

考虑以下最小示例:

>>> '/'.split('/')
['', '']

split必须给您定界符前后的内容'/',但没有其他字符。因此,它必须为您提供一个空字符串,从技术上讲,它在之前和之后'/',因为'' + '/' + '' == '/'

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.