2008-11-01 8 views
5

Ben aşağıdaki satırı vardır: Basit Regexp'i kullanarak bu ayrıştırmakİntikamımı açgözlü bir niceleyici ile çok fazla eşleşmemesi için nasıl giderebilirim?

"14:48 say;0ed673079715c343281355c2a1fde843;2;laka;hello ;)" 

:

if($line =~ /(\d+:\d+)\ssay;(.*);(.*);(.*);(.*)/) { 
    my($ts, $hash, $pid, $handle, $quote) = ($1, $2, $3, $4, $5); 
} 

Ama; sonunda şeyleri berbat eder ve nedenini bilmiyorum. Açgözlü operatör "her şey" işlemez mi? İlk 3 (.*) ungreedy (.*?)

cevap

18

iyi açgözlü operatörü ve hala dize eşleşebilir kadar malzeme olarak ele geçirmeye çalışır çalışmalıdır. Neler oluyor? İlk önce ("diyelim") kapmak "0ed673079715c343281355c2a1fde843; 2", ikincisi "laka" alır, üçüncü "merhaba" bulur ve dördüncü parantezle eşleşir.

Ne yapmak gerek sonuncusu olmayan açgözlü, ancak tüm yapmak, bu yüzden mümkün olduğunca az kapmak ve hala dizeyle eşleşen: Bir ekleyerek * olmayan açgözlü yapabilir

(\d+:\d+)\ssay;(.*?);(.*?);(.*?);(.*) 
+0

Bu harika! Bana hızlı arasındaki farkı söyleyebilir misin. % 0 * Teşekkürler! :) –

+1

Farkı bu. *?aşağıdakileri takip eden ilk durumda durur, oysa. * aşağıdakilerin son durumunda durur. – eyelidlessness

+0

Ah, harika insanlar! Takdir ederim! :-) –

7
(\d+:\d+)\ssay;([^;]*);([^;]*);([^;]*);(.*) 

yapma

+0

Sanırım fazladan var ([^;] *); Bence son bölüm, "Merhaba;)" – Ady

+0

Ady: Right: Bir sonraki satırın geri kalanını almak için son kısım (. *) Kadar basit olabilir. Sabit – VonC

2

soru işareti:

$line =~ /(\d+:\d+)\ssay;(.*?);(.*?);(.*?);(.*)/ 

veya Sonuncusu hariç her bölümünde bir noktalı virgül hariç her şeyi eşleşebilir:

$line =~ /(\d+:\d+)\ssay;([^;]*);([^;]*);([^;]*);(.*)/ 
7

Bir regex bunu kolayca yapabilir, ancak en doğru yaklaşım olduğundan emin değilim. Muhtemelen en kısa olanıdır, ama bu aslında onu en iyi şekilde sürdüremez. Bu sadece biraz daha okunabilir olduğunu düşünüyorum

[14:48],[say],[0ed673079715c343281355c2a1fde843],[2],[laka],[hello ;)] 

Bunun neticesinde:

$x="14:48 say;0ed673079715c343281355c2a1fde843;2;laka;hello ;)"; 

if (($ts,$rest) = $x =~ /(\d+:\d+)\s+(.*)/) 
{ 
    my($command,$hash,$pid,$handle,$quote) = split /;/, $rest, 5; 
    print join ",", map { "[$_]" } $ts,$command,$hash,$pid,$handle,$quote 
} 

:

Bunun yerine, böyle bir şey önermek istiyorum. Sadece bu değil, aynı zamanda hata ayıklamak ve korumak da daha kolay, çünkü bir insan aynı şeyi kalem ve kağıt ile denemek isterse, bunu nasıl yapacağınıza daha yakındır. Dizgiyi daha sonra ayrıştırabileceğiniz parçalara ayırın - bilgisayarın tam olarak ne yapacağını yapın. Değişiklik yapma zamanı geldiğinde, bunun daha iyi olacağını düşünüyorum. YMMV.

3

Noktalı virgülle ayrılmış listenizdeki değerler herhangi bir noktalı virgülü kendilemezse, bunu yazarak en verimli ve basit düzenli ifadeyi alırsınız. Belli değerler yalnızca bir altıgen karakter dizisi olabilirse, bunu yazınız. Tembel veya açgözlü bir nokta kullanan çözümler, regex konu dizgisiyle eşleşmediğinde her zaman işe yaramaz bir geri dönüşüme yol açar.

(\d+:\d+)\ssay;([a-f0-9]+);(\d+);(\w+);([^;\r\n]+) 
+0

Jan, bir şeyin kaynak kodu olarak işaretlenmesini istiyorsanız, her satırın dört boşlukla başlaması gerekir. Ve SO'ya hoş geldiniz. –

İlgili konular