第一次出现时分裂

Aco*_*orn 273 python split

在第一次出现分隔符时拆分字符串的最佳方法是什么?

例如:

"123mango abcd mango kiwi peach"
Run Code Online (Sandbox Code Playgroud)

分裂第一个mango得到:

"abcd mango kiwi peach"
Run Code Online (Sandbox Code Playgroud)

Ign*_*ams 462

来自文档:

str.split([sep[, maxsplit]])

使用sep作为分隔符字符串,返回字符串中单词的列表.如果给出maxsplit,则最多完成maxsplit拆分(因此,列表将具有最多maxsplit+1元素).

s.split('mango', 1)[1]
Run Code Online (Sandbox Code Playgroud)

  • 注意:如果在达到“maxsplit”计数后可以执行更多拆分,则列表中的最后一个元素将包含字符串的其余部分(包括任何“sep”字符/字符串)。 (2认同)

utd*_*mir 61

>>> s = "123mango abcd mango kiwi peach"
>>> s.split("mango", 1)
['123', ' abcd mango kiwi peach']
>>> s.split("mango", 1)[1]
' abcd mango kiwi peach'
Run Code Online (Sandbox Code Playgroud)

  • @Swiss:那是什么.技术仍然相同. (8认同)
  • @Ignacio:我只是指出来了.没有理由得到部分正确的答案来代替完全正确的答案. (6认同)
  • @AlvaroParra 好吧,是的;如果您使用 Pandas Series 的 .split 方法,它的工作方式将与内置字符串的 .split 方法不同。 (2认同)

Ale*_*lex 27

对我来说,更好的方法是:

s.split('mango', 1)[-1]
Run Code Online (Sandbox Code Playgroud)

...因为如果发生这种情况不在你将得到的字符串中" IndexError: list index out of range".

因此-1不会造成任何伤害,因为发生次数已经设置为1.

  • 如前所述,它是应用 split() 方法的出现次数。方法将仅查找并应用第一个 'mango' 字符串。 (2认同)

hee*_*ayl 8

您还可以使用str.partition

>>> text = "123mango abcd mango kiwi peach"

>>> text.partition("mango")
('123', 'mango', ' abcd mango kiwi peach')

>>> text.partition("mango")[-1]
' abcd mango kiwi peach'

>>> text.partition("mango")[-1].lstrip()  # if whitespace strip-ing is needed
'abcd mango kiwi peach'
Run Code Online (Sandbox Code Playgroud)

使用的好处str.partition是它总是会以以下形式返回一个元组:

(<pre>, <separator>, <post>)
Run Code Online (Sandbox Code Playgroud)

所以这使得解包输出非常灵活,因为结果元组中总是会有 3 个元素。

  • 如果某些行只有一个键,这对于从一行文本创建键值对非常有用,因为正如您所指出的,您总是得到一个元组:`key, _, value = text_line.partition(' ')` (2认同)
  • 您甚至可以使用切片忽略元组中的分隔符,使用单行:`key, value = text_line.partition(' ')[::2]` (2认同)

Kar*_*tel 6

概括

最简单且性能最好的方法是使用.partition字符串的方法

通常,人们可能想要获取找到的分隔符之前之后的部分,并且可能想要查找字符串中第一次最后一次出现的分隔符。对于大多数技术来说,所有这些可能性都大致一样简单,并且从一种技术转换为另一种技术也很简单。

对于以下示例,我们将假设:

>>> import re
>>> s = '123mango abcd mango kiwi peach'
Run Code Online (Sandbox Code Playgroud)

使用.split

>>> s.split('mango', 1)
['123', ' abcd mango kiwi peach']
Run Code Online (Sandbox Code Playgroud)

第二个参数.split限制字符串被分割的次数。这给出了分隔符之前和之后的部分;然后我们就可以选择我们想要的。

如果分隔符没有出现,则不进行分割:

>>> s.split('grape', 1)
['123mango abcd mango kiwi peach']
Thus, to check whether the delimiter was present, check the length of the result before working with it.
Run Code Online (Sandbox Code Playgroud)

使用.partition

>>> s.partition('mango')
('123', 'mango', ' abcd mango kiwi peach')
Run Code Online (Sandbox Code Playgroud)

结果是一个元组,并且分隔符本身在找到时被保留。

当没有找到分隔符时,结果将是一个相同长度的元组,结果中有两个空字符串:

>>> s.partition('grape')
('123mango abcd mango kiwi peach', '', '')
Run Code Online (Sandbox Code Playgroud)

因此,要检查分隔符是否存在,请检查第二个元素的值。

使用正则表达式

>>> # Using the top-level module functionality
>>> re.split(re.escape('mango'), s, 1)
['123', ' abcd mango kiwi peach']
>>> # Using an explicitly compiled pattern
>>> mango = re.compile(re.escape('mango'))
>>> mango.split(s, 1)
['123', ' abcd mango kiwi peach']
Run Code Online (Sandbox Code Playgroud)

正则表达式的方法.split与内置字符串.split方法具有相同的参数,以限制分割次数。同样,当分隔符不出现时,不会进行分割:

>>> grape = re.compile(re.escape('grape'))
>>> grape.split(s, 1)
['123mango abcd mango kiwi peach']
Run Code Online (Sandbox Code Playgroud)

在这些示例中,re.escape没有任何效果,但在一般情况下,为了将分隔符指定为文字文本,有必要这样做。另一方面,使用该re模块可以发挥正则表达式的全部功能:

>>> vowels = re.compile('[aeiou]')
>>> # Split on any vowel, without a limit on the number of splits:
>>> vowels.split(s)
['123m', 'ng', ' ', 'bcd m', 'ng', ' k', 'w', ' p', '', 'ch']
Run Code Online (Sandbox Code Playgroud)

e(注意空字符串:在 the和aof之间找到peach。)

使用索引和切片

使用.index字符串的方法找出分隔符在哪里,然后用它进行切片:

>>> s[:s.index('mango')] # for everything before the delimiter
'123'
>>> s[s.index('mango')+len('mango'):] # for everything after the delimiter
' abcd mango kiwi peach'
Run Code Online (Sandbox Code Playgroud)

这直接给出了前缀。但是,如果未找到分隔符,则会引发异常:

>>> s[:s.index('grape')]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: substring not found
Run Code Online (Sandbox Code Playgroud)

最后一次出现之后的所有内容

虽然没有人问,但我在这里提供了相关技术以供参考。

和技术有直接.split.partition对应项,用于获取字符串的最后一部分(即,最后一次出现分隔符之后的所有内容)。以供参考:

>>> '123mango abcd mango kiwi peach'.rsplit('mango', 1)
['123mango abcd ', ' kiwi peach']
>>> '123mango abcd mango kiwi peach'.rpartition('mango')
('123mango abcd ', 'mango', ' kiwi peach')
Run Code Online (Sandbox Code Playgroud)

类似地,有一个.rindexto match ,但它仍然会给出分区最后一个匹配的开头.index索引。因此:

>>> s[:s.rindex('mango')] # everything before the last match
'123mango abcd '
>>> s[s.rindex('mango')+len('mango'):] # everything after the last match
' kiwi peach'
Run Code Online (Sandbox Code Playgroud)

对于正则表达式方法,我们可以依靠反转输入的技术,查找反转分隔符的第一次出现,反转各个结果,然后反转结果列表:

>>> ognam = re.compile(re.escape('mango'[::-1]))
>>> [x[::-1] for x in ognam.split('123mango abcd mango kiwi peach'[::-1], 1)][::-1]
['123mango abcd ', ' kiwi peach']
Run Code Online (Sandbox Code Playgroud)

当然,几乎可以肯定,这付出的努力超过了其价值。

另一种方法是从分隔符到字符串末尾使用负向前查找:

>>> literal_mango = re.escape('mango')
>>> last_mango = re.compile(f'{literal_mango}(?!.*{literal_mango})')
>>> last_mango.split('123mango abcd mango kiwi peach', 1)
['123mango abcd ', ' kiwi peach']
Run Code Online (Sandbox Code Playgroud)

由于前瞻,这是最坏情况的 O(n^2) 算法。

性能测试

$ python -m timeit --setup="s='123mango abcd mango kiwi peach'" "s.partition('mango')[-1]"
2000000 loops, best of 5: 128 nsec per loop
$ python -m timeit --setup="s='123mango abcd mango kiwi peach'" "s.split('mango', 1)[-1]"
2000000 loops, best of 5: 157 nsec per loop
$ python -m timeit --setup="s='123mango abcd mango kiwi peach'" "s[s.index('mango')+len('mango'):]"
1000000 loops, best of 5: 250 nsec per loop
$ python -m timeit --setup="s='123mango abcd mango kiwi peach'; import re; mango=re.compile(re.escape('mango'))" "mango.split(s, 1)[-1]"
1000000 loops, best of 5: 258 nsec per loop
Run Code Online (Sandbox Code Playgroud)

虽然更灵活,但正则表达式方法肯定更慢。限制分割数量可以提高字符串方法和正则表达式的性能(没有显示没有限制的时间,因为它们速度较慢并且也会给出不同的结果),但是.partition仍然是明显的赢家。

对于这一测试数据,该.index方法速度较慢,即使它只需要创建一个子字符串,并且不必迭代超出匹配范围的文本(为了创建其他子字符串)。预先计算分隔符的长度会有所帮助,但这仍然比.split.partition方法慢。