当它可能不包含模式或全部n个元素时,如何在Python中可靠地拆分字符串?


77

在Perl中,我可以执行以下操作:

my ($x, $y) = split /:/, $str;

无论字符串是否包含模式,它都将起作用。

但是在Python中,这将不起作用:

a, b = "foo".split(":")  # ValueError: not enough values to unpack

在这种情况下,防止错误的规范方法是什么?


4
在Perl中,什么$x$y得到,如果字符串不包含的格局?他们两个都分配了整个字符串,还是$y得到null或其他东西?
不要惊慌

6
@ Don'tPanic:$x获得了整个字符串,$yundef(这是类似None的,但略有不同)。
cdarke '16

4
@ jpmc26:在Perl中,它将忽略其他值。但是我怀疑我们是否真的想用python写一个Perl仿真器。
cdarke '16

7
@cdarke当然我们不是在编写Perl仿真器,但是如果不知道所需的行为是什么,我们就无法回答问题。他们从该问题中忽略的OP代码的一个重要方面是,如果字符串包含多个冒号,则Python版本也会失败。无论如何,文档似乎与您矛盾。看起来Perl返回一个列表,该列表在每次出现模式时都会拆分,与Python的split功能相同。还似乎Perlsplit正在接受正则表达式。
jpmc26 2016年

2
@ jpmc26 Perl列表与python列表不同,它更接近元组,除了在perl中不能有类型为list的变量之外,也不能引用一个。Perl中的列表实际上仅是一种语法设备。这里有一个讨论: Friedo.com/blog/2013/07/arrays-vs-lists-in-perl。是的,除了对空格有额外的魔力之外,Perlsplit更接近re.split
cdarke '16

Answers:


111

如果您仅分成两部分(例如您的示例),则可以使用str.partition()得到的有保证的参数拆包大小为3:

>>> a, sep, b = 'foo'.partition(':')
>>> a, sep, b
('foo', '', '')

str.partition() 无论是否找到分隔符,总是返回一个三元组。

Python 3.x的另一种选择是使用扩展的可迭代拆包

>>> a, *b = 'foo'.split(':')
>>> a, b
('foo', [])

这会将第一个拆分项目分配给,并将a剩余项目列表(如果有)分配给b


59

由于您使用的是Python 3,因此很容易。PEP 3132在分配给元组时引入了令人欢迎的语法简化-扩展的可迭代拆包。过去,如果在元组中分配变量,则分配左侧的项目数必须与右侧的完全相同。

在Python 3中,我们可以在前面加上星号*的形式将左侧的任何变量指定为列表。这将获取尽可能多的值,同时仍将变量填充到其右边(因此它不必是最右边的项)。当我们不知道元组的长度时,这避免了很多讨厌的切片。

a, *b = "foo".split(":")  
print("a:", a, "b:", b)

给出:

a: foo b: []

编辑以下评论和讨论:

与Perl版本相比,这有很大不同,但这是Python(3)方式。与Perl版本相比,它re.split()会更相似,但是调用RE引擎拆分单个字符是不必要的开销。

在Python中包含多个元素:

s = 'hello:world:sailor'
a, *b = s.split(":")
print("a:", a, "b:", b)

给出:

a: hello b: ['world', 'sailor']

但是在Perl中:

my $s = 'hello:world:sailor';
my ($a, $b) = split /:/, $s;
print "a: $a b: $b\n";

给出:

a: hello b: world

可以看出,在Perl中,其他元素被忽略或丢失。如果需要,可以很容易地在Python中复制它:

s = 'hello:world:sailor'
a, *b = s.split(":")
b = b[0]
print("a:", a, "b:", b)

因此,a, *b = s.split(":")Perl中的等效项为

my ($a, @b) = split /:/, $s;

注意:我们不应该使用Perl$a$bPerl,因为它们与一起使用具有特殊含义sort。我在这里使用它们是为了与Python示例保持一致。

Python确实有一个额外的窍门,我们可以解压缩到左侧元组中的任何元素:

s = "one:two:three:four"
a, *b, c = s.split(':')
print("a:", a, "b:", b, "c:", c)

给出:

a: one b: ['two', 'three'] c: four

而在Perl中,数组(@b)是贪婪的,标量$cundef

use strict;
use warnings;

my $s = 'one:two:three:four';
my ($a, @b, $c) = split /:/, $s;
print "a: $a b: @b c: $c\n";

给出:

Use of uninitialized value $c in concatenation (.) or string at gash.pl line 8.
a: one b: two three four c: 

如果将变量放在右边,它将如何工作b
Panzercrisis '16

3
@Panzercrisis它很健壮-a,*b,c = "foo:bar:baz:last".split(":")提供a="foo" b=["bar","baz"] c="last"编辑:如果您没有为确定的事情提供足够的值,它将死掉,即与"foo"被分裂的语句相同ValueError: not enough values to unpack (expected at least 2, got 1)
Delioth '16

1
@magu_它做不同的事情。str.partition仅执行一次拆分。因此,就像过去了maxsplit=1
巴库里

1
@ jpmc26:不完全是。在Perl中,如果将结果分配split()给两个标量,则将得到两个字符串,或者一个字符串和一个undef,但是不会得到一个字符串和数组引用。
Eugene Yarmash '16

2
@magu_,这是因为Python 3比Python 2更具有
Pythonic

21

您总是可以随时捕获异常。

例如:

some_string = "foo"

try:
    a, b = some_string.split(":")
except ValueError:
    a = some_string
    b = ""

如果希望将整个原始字符串分配给,a并将空字符串分配给b,则我可能会使用str.partition()eugene y的建议。但是,此解决方案使您可以更好地控制字符串中没有分隔符时发生的情况,这在某些情况下可能很有用。


3
如果字符串包含多个定界符,则将无法正常工作,例如,'a:b:c:d:e'
jpmc26 '16

17

split将始终返回列表。a, b = ...总是希望列表长度为2。您可以使用l = string.split(':'); a = l[0]; ...

这是一个班轮: a, b = (string.split(':') + [None]*2)[:2]


4

如何使用正则表达式:

import re 
string = 'one:two:three:four'

在3.X中:

a, *b = re.split(':', string)

在2.X中:

a, b = re.split(':', string)[0], re.split(':', string)[1:]

这样,您还可以使用正则表达式进行拆分(即\ d)

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.