Как надежно разделить строку в Python?
в Perl я могу сделать:
my ($x, $y) = split /:/, $str;
и он будет работать независимо от того, содержит ли строка шаблон.
в Python, однако это не будет работать:
a, b = "foo".split(":") # ValueError: not enough values to unpack
каков канонический способ предотвращения ошибок в таких случаях?
5 ответов:
если вы разбиваете на две части (как в вашем примере), вы можете использовать
str.partition()чтобы получить гарантированный аргумент размер распаковки 3:>>> a, sep, b = "foo".partition(":") >>> a, sep, b ('foo', '', '')
str.partition()всегда возвращает 3-кортеж, независимо от того, найден разделитель или нет.Другой альтернативой для Python 3 является использование расширенной распаковки, как описано в @cdarke это:
>>> a, *b = "foo".split(":") >>> a, b ('foo', [])это присваивает первый разделенный элемент
aи список остальных пунктов (если есть)b.
так как вы находитесь на 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;NB: мы не следует использовать
$aи$bв общем на Perl, так как они имеют особое значение при использовании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) является жадным, и скаляра$cisundef: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:
вы всегда можете поймать исключение.
например:
some_string = "foo" try: a, b = some_string.split(":") except ValueError: a = some_string b = ""если присвоить всю исходную строку
aи пустая строка вbэто желаемое поведение, я бы, вероятно, использоватьstr.partition()как предлагает Евгений Ю. Однако это решение дает вам больше контроля над тем, что именно происходит, когда в строке нет разделителя, что может быть полезно в некоторых случаях.
splitвсегда будет возвращать список.a, b = ...всегда ожидать, что длина списка будет два. Вы можете использовать что-то вродеl = string.split(':'); a = l[0]; ....вот один лайнер:
a, b = (string.split(':') + [None]*2)[:2]
как насчет использования регулярных выражений:
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)
Comments