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

时间:2016-07-01 15:50:24

标签: python string python-3.x split

在Perl我能做到:

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

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

在Python中,但这不起作用:

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

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

5 个答案:

答案 0 :(得分:111)

如果您只分成两个部分(例如在您的示例中),您可以使用str.partition()来获得保证参数解包大小为3:

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

str.partition()始终返回3元组,无论是否找到分隔符。

Python 3.x的另一个替代方法是使用extended iterable unpacking

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

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

答案 1 :(得分:60)

由于您使用的是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)

因此,Perl中的a, *b = s.split(":")等价物将是

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

注意:我们不应该在一般Perl中使用$a$b,因为它们与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: 

答案 2 :(得分:22)

你总是可以自由地捕捉异常。

例如:

some_string = "foo"

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

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

答案 3 :(得分:17)

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

以下是单行班次:a, b = (string.split(':') + [None]*2)[:2]

答案 4 :(得分:3)

如何使用正则表达式:

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

这样你也可以使用正则表达式来分割(即e。\ d)