2010-03-18 5 views
12

$ str = "1: 2: 3: 4: 5"; my ($ a, $ b) = bölünmüş (':', $ str, 2);Perl dizesini sadece ayırıcının son oluşumuna nasıl bölebilirim?

Yukarıdaki kodda sınırı 2 olarak kullandım, böylece $ a 1 değerini içerecek ve kalan öğeler $ b olarak olacaktır. Bunun gibi Son öğenin bir değişkende olmasını ve son öğeden önceki öğelerin başka bir değişkende olmasını istiyorum.

Örnek

$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" 
+1

Yinelenen: http://stackoverflow.com/questions/1098295/perl-is-there-a-way-to-split-on-the-last-regex -match-only-only- – Zaid

cevap

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

Sen bölünmüş kullanarak bunu ve aşağıdaki gibi tersine çevirebilir:

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 

Şimdi $a 1:2:3:4 olacak ve $b 5 olacaktır.

Çok daha basit ve temiz bir yol, Mark'ın Cevabında yaptığı gibi normal ifadeyi kullanmaktır.

+1

Bu bir olasılık olsa da, özellikle tek bir hat eşdeğerde yapacağınız zaman, tam olarak verimli değildir. Benim gibi bir şey ($ a, $ b) = ($ str = ~ /(.*):(.?)/); ' – Zaid

7

de kullanabilirsiniz rindex() örn

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

çıkış

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

Bu durumda ayrık ayırıcı çok basit olduğundan, bu daha hızlı bir çözümdür tüm ifadeyi '$' ile bağlanmaya çalışarak ayırmak için bir regex. – Ether

6

yerine bölünmenin, eşleştirme kullanabilirsiniz:

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

Ben bunu yapmak için ikinci '. *' A '.?', Yapardım. – Zaid

2

, bu soru 4 yaşındadır . Ama ben cevabını çok ilginç bulmuştum, split bunun gibi çalışabiliyordu. Bu yüzden, bu davranışı yeni okuyucular için açıklayan perldoc split'dan bir özü ile genişletmek istiyorum. :-)

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

MODEL yakalama gruplarını, daha sonra her bir ayırıcı, ek bir alan için, (bir grup tarafından yakalanan her substring için üretilir içeriyorsa hangi gruplar, geri bildirimlere göre belirtilmiştir); Herhangi bir grup eşleşmezse, bir alt dize yerine undef değerini yakalar. Ayrıca, böyle bir ek alanın bir ayırıcı olduğunda (yani, bir bölünme olduğunda) üretildiğine ve böyle bir ek alanın LIMIT'e doğru sayılmadığına dikkat edin. Liste kapsamında değerlendirilen aşağıdaki ifadeleri düşünün (ilişkili açıklamada sağlanan her döndürülen liste):

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

Ben biraz geç bu soruya değilim, ama birlikte daha genel bir çözüm koydu:

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

Ayırma işleminin ters sırayla yapılması dışında split() benzeri argümanları kabul eder. Belirtilen sayıda sonuç öğesine ihtiyaç duymanız durumunda bir limit cümlesi de kabul eder.

Not: Bu alt yordam, ilk parametre olarak precompiled regex bekler.
Perl en split yerleşik bir olduğunu ve doğru /pat/ yorumlamak, ancak sub($_ =~ /pat/) olarak kabul edilmesini sağlayacak bir alt yordam /pat/ geçirmeye çalışıyor olacaktır.

Bu alt yordam, kurşun geçirmez değildir! Basit sınırlayıcılar için yeterince iyi çalışır, ancak daha karmaşık desenler sorunlara neden olabilir. Desenin kendisi tersine çevrilemez, sadece onunla eşleştiği ifade.


Örnekler:

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