如何仅在最后一次出现的分隔符上拆分Perl字符串?

时间:2010-03-18 10:27:37

标签: perl split

my $ str =“1:2:3:4:5”;     我的($ a,$ b)=拆分(':',$ 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"

6 个答案:

答案 0 :(得分:18)

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

答案 1 :(得分:8)

你也可以使用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

答案 2 :(得分:8)

您可以使用匹配,而不是分割:

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

答案 3 :(得分:3)

我知道,这个问题是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')

答案 4 :(得分:2)

您可以使用拆分和反向执行此操作,如下所示:

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

更简单,更简洁的方法是使用正则表达式,正如马克在他的答案中所做的那样。

答案 5 :(得分:-1)

我对这个问题有点迟了,但我总结了一个更通用的解决方案:

# 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()'s result array element order
    # 4) Reverse each string within the result array
    map { scalar reverse($_) } reverse split(/$pattern/, scalar reverse($expr), $limit);
}

它接受类似于split()的参数,除了拆分以相反的顺序完成。如果您需要指定数量的结果元素,它还接受限制子句。

注意:此子例程需要precompiled regex作为第一个参数。
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')