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

时间:2022-01-10 02:14:26

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

我的$ str =“1:2:3:4:5”;我的($ a,$ b)=拆分(':',$ str,2);

In the above code I have used limit as 2 ,so $a will contain 1 and remaining elements will be in $b. Like this I want the last element should be in one variable and the elements prior to the last element should be in another variable.

在上面的代码中,我使用limit作为2,因此$ a将包含1,其余元素将在$ b中。像这样我希望最后一个元素应该在一个变量中,而最后一个元素之前的元素应该在另一个变量中。

Example

$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 个解决方案

#1


17  

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

#2


8  

you can also use rindex() eg

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

output

产量

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

#3


7  

You can use matching, instead of split:

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

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

#4


2  

You can do it using split and reverse as follows:

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

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

Now $a will be 1:2:3:4 and $b will be 5.

现在$ a将是1:2:3:4而$ b将是5。

A much simpler and cleaner way is to use regex as Mark has done in his Answer.

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

#5


2  

I know, this question is 4 years old. But I found the answer from YOU very interesting as I didn't know split could work like that. So I want to expand it with an extract from the perldoc split that explains this behavior, for the sake of new readers. :-)

我知道,这个问题是4岁。但我发现你的回答非常有趣,因为我不知道分裂可能会那样。因此,为了新读者的缘故,我想用perldoc拆分的摘录来扩展它,解释这种行为。 :-)

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';

From Perldoc:

来自Perldoc:

If the PATTERN contains capturing groups, then for each separator, an additional field is produced for each substring captured by a group (in the order in which the groups are specified, as per backreferences); if any group does not match, then it captures the undef value instead of a substring. Also, note that any such additional field is produced whenever there is a separator (that is, whenever a split occurs), and such an additional field does not count towards the LIMIT. Consider the following expressions evaluated in list context (each returned list is provided in the associated comment):

如果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')

#6


0  

I'm a bit late to this question, but I put together a more generic solution:

我对这个问题有点迟,但我把一个更通用的解决方案放在一起:

# 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);
}

It accepts arguments similar to split() except that the splitting is done in reverse order. It also accepts a limit clause in case you need a specified number of result elements.

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

Note: this subroutine expects a precompiled regex as the first parameter.
Perl's split is a built-in and will interpret /pat/ correctly, but attempting to pass /pat/ to a subroutine will be treated as sub($_ =~ /pat/).

注意:此子例程需要预编译的正则表达式作为第一个参数。 Perl的拆分是内置的并且会正确解释/ pat /,但是尝试传递/ pat /到子例程将被视为sub($ _ =〜/ pat /)。

This subroutine is not bulletproof! It works well enough for simple delimiters but more complicated patterns can cause issues. The pattern itself cannot be reversed, only the expression it matches against.

这个子程序不是防弹的!它适用于简单的分隔符,但更复杂的模式可能会导致问题。模式本身不能反转,只能反映它所匹配的表达式。


Examples:

例子:

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')

#1


17  

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

#2


8  

you can also use rindex() eg

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

output

产量

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

#3


7  

You can use matching, instead of split:

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

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

#4


2  

You can do it using split and reverse as follows:

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

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

Now $a will be 1:2:3:4 and $b will be 5.

现在$ a将是1:2:3:4而$ b将是5。

A much simpler and cleaner way is to use regex as Mark has done in his Answer.

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

#5


2  

I know, this question is 4 years old. But I found the answer from YOU very interesting as I didn't know split could work like that. So I want to expand it with an extract from the perldoc split that explains this behavior, for the sake of new readers. :-)

我知道,这个问题是4岁。但我发现你的回答非常有趣,因为我不知道分裂可能会那样。因此,为了新读者的缘故,我想用perldoc拆分的摘录来扩展它,解释这种行为。 :-)

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';

From Perldoc:

来自Perldoc:

If the PATTERN contains capturing groups, then for each separator, an additional field is produced for each substring captured by a group (in the order in which the groups are specified, as per backreferences); if any group does not match, then it captures the undef value instead of a substring. Also, note that any such additional field is produced whenever there is a separator (that is, whenever a split occurs), and such an additional field does not count towards the LIMIT. Consider the following expressions evaluated in list context (each returned list is provided in the associated comment):

如果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')

#6


0  

I'm a bit late to this question, but I put together a more generic solution:

我对这个问题有点迟,但我把一个更通用的解决方案放在一起:

# 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);
}

It accepts arguments similar to split() except that the splitting is done in reverse order. It also accepts a limit clause in case you need a specified number of result elements.

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

Note: this subroutine expects a precompiled regex as the first parameter.
Perl's split is a built-in and will interpret /pat/ correctly, but attempting to pass /pat/ to a subroutine will be treated as sub($_ =~ /pat/).

注意:此子例程需要预编译的正则表达式作为第一个参数。 Perl的拆分是内置的并且会正确解释/ pat /,但是尝试传递/ pat /到子例程将被视为sub($ _ =〜/ pat /)。

This subroutine is not bulletproof! It works well enough for simple delimiters but more complicated patterns can cause issues. The pattern itself cannot be reversed, only the expression it matches against.

这个子程序不是防弹的!它适用于简单的分隔符,但更复杂的模式可能会导致问题。模式本身不能反转,只能反映它所匹配的表达式。


Examples:

例子:

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')