Подтвердить что ты не робот

Как я могу разбить строку Perl только на последнее вхождение разделителя?

my $str = "1: 2: 3: 4: 5";   my ($ a, $b) = split (':', $str, 2);

В приведенном выше коде я использовал limit как 2, поэтому $a будет содержать 1, а остальные элементы будут в $b. Подобно этому, я хочу, чтобы последний элемент находился в одной переменной, а элементы до последнего элемента должны быть в другой переменной.

Пример

$str = "1:2:3:4:5" ; 
# $a should have "1:2:3:4"  and $b should have "5" 
$str =  "2:3:4:5:3:2:5:5:3:2" 
# $a should have "2:3:4:5:3:2:5:5:3" and $b should have "2"
4b9b3361

Ответ 1

split(/:([^:]+)$/, $str)

Ответ 2

вы также можете использовать rindex() например

my $str="1:2:3:4:5";
$i=rindex($str,":");
$a=substr($str,0,$i);
$b=substr($str,$i+1);
print "\$a:$a, \$b: $b\n";

Выход

$ perl perl.pl
$a:1:2:3:4, $b: 5

Ответ 3

Вы можете использовать сопоставление с шаблоном вместо split():

my ($a, $b) = $str =~ /(.*):(.*)/;

Первая группа захватывает все до последнего появления символа ':', а вторая группа захватывает все остальное.

В случае, если ':' нет в строке, Perl достаточно умен, чтобы обнаружить, что и не матч без возвратов.

Ответ 4

Я знаю, этот вопрос составляет 4 года. Но я нашел ответ от YOU очень интересным, поскольку я не знал, что split может работать так. Поэтому я хочу расширить его с помощью выдержки из perldoc split, которая объясняет это поведение ради новых читателей.: -)

my $str = "1:2:3:4:5";
my ($a, $b) = split /:([^:]+)$/, $str;
# Capturing everything after ':' that is not ':' and until the end of the string
# Now $a = '1:2:3:4' and $b = '5';

От Perldoc:

Если PATTERN содержит группы захвата, то для каждого разделителя создается дополнительное поле для каждой подстроки, захваченной группой (в том порядке, в котором указаны группы, в соответствии с обратными ссылками); если какая-либо группа не соответствует, то она захватывает значение undef вместо подстроки. Также обратите внимание, что любое такое дополнительное поле создается всякий раз, когда есть разделитель (т.е. Всякий раз, когда происходит сплит), и такое дополнительное поле не учитывается в LIMIT. Рассмотрим следующие выражения, оцененные в контексте списка (каждый возвращенный список указан в соответствующем комментарии):

split(/-|,/, "1-10,20", 3)
# ('1', '10', '20')

split(/(-|,)/, "1-10,20", 3)
# ('1', '-', '10', ',', '20')

split(/-|(,)/, "1-10,20", 3)
# ('1', undef, '10', ',', '20')

split(/(-)|,/, "1-10,20", 3)
# ('1', '-', '10', undef, '20')

split(/(-)|(,)/, "1-10,20", 3)
# ('1', '-', undef, '10', undef, ',', '20')

Ответ 5

Вы можете сделать это с помощью split и reverse следующим образом:

my $str="1:2:3:4:5";
my ($a,$b)=split(':',reverse($str),2); # reverse and split.

$a = reverse($a); # reverse each piece.
$b = reverse($b);

($a,$b) = ($b,$a); # swap a and b

Теперь $a будет 1:2:3:4, а $b будет 5.

Более простой и понятный способ - использовать регулярное выражение, как это сделал Марк в своем ответе.

Ответ 6

Я немного опаздываю на этот вопрос, но я собрал более общее решение:

# Similar to split() except pattern is applied backwards from the end of the string
# The only exception is that the pattern must be a precompiled regex (i.e. qr/pattern/)
# Example:
#   rsplit(qr/:/, 'John:Smith:123:ABC', 3) => ('John:Smith', '123', 'ABC')
sub rsplit {
    my $pattern = shift(@_);    # Precompiled regex pattern (i.e. qr/pattern/)
    my $expr    = shift(@_);    # String to split
    my $limit   = shift(@_);    # Number of chunks to split into

    # 1) Reverse the input string
    # 2) split() it
    # 3) Reverse split() result array element order
    # 4) Reverse each string within the result array
    map { scalar reverse($_) } reverse split(/$pattern/, scalar reverse($expr), $limit);
}

Он принимает аргументы, подобные split(), за исключением того, что расщепление выполняется в обратном порядке. Он также принимает предложение limit, если вам нужно определенное количество элементов результата.

Примечание. Эта подпрограмма ожидает, что в качестве первого параметра предварительно скомпилированное регулярное выражение.
Perl split является встроенным и будет правильно интерпретировать /pat/, но попытка передать /pat/ в подпрограмму будет считаться sub($_ =~ /pat/).

Эта подпрограмма не является пуленепробиваемой! Он работает достаточно хорошо для простых разделителей, но более сложные шаблоны могут вызвать проблемы. Сам шаблон не может быть отменен, только выражение, в котором оно соответствует.


Примеры:

rsplit(qr/:/, 'One:Two:Three', 2); # => ('One:Two', 'Three')

rsplit(qr/:+/, 'One:Two::Three:::Four', 3); # => ('One:Two', 'Three', 'Four')

# Discards leading blank elements just like split() discards trailing blanks
rsplit(qr/:/, ':::foo:bar:baz'); # => ('foo', 'bar', 'baz')