Java normal ifade yakalama grupları dizinleri


113

Aşağıdaki satıra sahibim

typeName="ABC:xxxxx;";

Kelimesini getirmek gerekir ABC,

Aşağıdaki kod parçacığını yazdım,

Pattern pattern4=Pattern.compile("(.*):");
matcher=pattern4.matcher(typeName);

String nameStr="";
if(matcher.find())
{
    nameStr=matcher.group(1);

}

Bu yüzden koyarsanız group(0)alıyorum ABC:ama ben koyarsanız group(1)o ABCbilmek istiyorum böylece,

  1. Bu ne geliyor 0ve 1ortalama? Birinin bana güzel örneklerle açıklaması daha iyi olacak.

  2. Normal ifade kalıbı içinde bir içeriyor :, öyleyse neden group(1)sonuç bunu göz ardı ediyor? Grup 1, parantez içindeki tüm kelimeleri algılıyor mu?

  3. Öyleyse, gibi iki parantez daha koyarsam \\s*(\d*)(.*): o zaman, iki grup olacak mı? parçayı group(1)iade edecek ve (\d*)parçayı group(2)iade edecek (.*)mi?

Kod parçacığı, kafa karışıklıklarımı gidermek için verildi. Benim uğraştığım kod değil. Yukarıda verilen kod ile String.split()çok daha kolay bir şekilde yapılabilir.

Yanıtlar:


182

Yakalama ve gruplama

Grup yakalama (pattern) Bir yaratır grubu vardır yakalama özelliği.

Sık sık (bkz ve kullanım) diye İlgili bir tanesidir (?:pattern)bir oluşturur, grup olmadan yakalama özelliği dolayısıyla adlı dışı yakalayan grup .

Bir grup genellikle bir kalıp dizisini tekrarlamanız gerektiğinde kullanılır, örneğin (\.\w+)+, veya değişimin nerede etkili olacağını belirtmek için, örneğin ^(0*1|1*0)$( ^sonra 0*1veya 1*0sonra $) ve ^0*1|1*0$( ^0*1veya 1*0$).

Gruplama dışında bir yakalama grubu, yakalama grubu içindeki modelle eşleşen metni de kaydedecektir (pattern). Örneğinizi kullanarak (.*):, .*eşleşmeler ABCve :eşleşmeler :ve .*yakalama grubunun içinde olduğu için, (.*)metin ABCyakalama grubu 1 için kaydedilir.

Grup numarası

Tüm model, grup numarası 0 olarak tanımlanmıştır .

Modeldeki herhangi bir yakalama grubu, indekslemeye 1'den başlar. Endeksler , yakalama gruplarının açılış parantezlerinin sırasına göre tanımlanır . Örnek olarak, aşağıdaki düzende bulunan 5 yakalama grubunun tümü :

(group)(?:non-capturing-group)(g(?:ro|u)p( (nested)inside)(another)group)(?=assertion)
|     |                       |          | |      |      ||       |     |
1-----1                       |          | 4------4      |5-------5     |
                              |          3---------------3              |
                              2-----------------------------------------2

Grup numaraları, \nmodelde geri referans ve $ndeğiştirme dizesinde kullanılır.

Diğer normal ifade çeşitlerinde (PCRE, Perl), alt rutin çağrılarda da kullanılabilirler .

İle belirli grupların eşleştiği metne erişebilirsiniz Matcher.group(int group). Grup numaraları yukarıda belirtilen kuralla tanımlanabilir.

Bazı regex tatlar (PCRE, Perl) olarak, bir orada şube sıfırlama kullanmak için izin verir özellik aynı numarayı için arda gelişinde farklı dallarında grupları yakalamak .

Grup ismi

Java 7'den adlandırılmış bir yakalama grubu tanımlayabilir (?<name>pattern)ve eşleşen içeriğe erişebilirsiniz Matcher.group(String name). Normal ifade daha uzundur, ancak normal ifadeyle neyi eşleştirmeye veya çıkarmaya çalıştığınızı gösterdiği için kod daha anlamlıdır.

Grup isimleri, \k<name>modelde geri referans ve ${name}değiştirme dizgesinde kullanılır.

Adlandırılmış yakalama grupları hala aynı numaralandırma şeması ile numaralandırılmıştır, bu nedenle bunlara da erişim sağlanabilir Matcher.group(int group).

Dahili olarak, Java'nın uygulaması sadece isimden grup numarasına eşlenir. Bu nedenle, 2 farklı yakalama grubu için aynı adı kullanamazsınız.


1
VAOV! Yakalamayan grupları iç içe yerleştirme grubu düzeninin nasıl çalıştığını açıkladığınız için @ nhahtdh'e teşekkür ederiz. Sonunda açıklamanızı okuyana kadar grup numaralarının nasıl çalıştığı konusunda şaşkındım. Çok teşekkürler!
MMeah

92

Geri kalanlarımız için

İşte bunun nasıl çalıştığına dair basit ve net bir örnek

regex: ([a-zA-Z0-9]+)([\s]+)([a-zA-Z ]+)([\s]+)([0-9]+)

Dize: "!* UserName10 John Smith 01123 *!"

group(0): UserName10 John Smith 01123
group(1): UserName10
group(2):  
group(3): John Smith
group(4):  
group(5): 01123

Gördüğünüz gibi, her biri parantez içine alınmış BEŞ grup oluşturdum.

! * Ve *! daha net hale getirmek için her iki tarafta. Bu karakterlerden hiçbirinin Normal İfadede bulunmadığını ve bu nedenle sonuçlarda üretilmeyeceğini unutmayın. Grup (0) yalnızca eşleşen dizenin tamamını (tüm arama kriterlerimi tek bir satırda) verir. Grup 1, boşluk karakteri arama kriterine dahil edilmediğinden, ilk boşluktan hemen önce durur. Grup 2 ve 4 basitçe beyaz boşluktur, bu durumda kelimenin tam anlamıyla bir boşluk karakteri olabilir, ancak aynı zamanda bir sekme veya satır beslemesi de olabilir. Grup 3, boşlukları içerir çünkü onu arama kriterlerine koydum ... vb.

Umarım bu mantıklıdır.


1
yeni başlayanlar için anlaşılması kolay mükemmel bir örnek. Bunun python'daki reg ex gruplama ile aynı olduğundan şüpheliyim? yoksa herhangi bir fark var mı? Reg ex'de yeniyim, bu yüzden her iki dilde de biraz kafam karışık.
Mani

1
Bu geçerli bir Java normal ifadesi değildir: ters eğik çizgiler iki katına çıkarılmalıdır.
Nicolas Raoul

1
@NicolasRaoul: Çift ters eğik çizgi, dize değişmezindeki kaçış sözdiziminden kaynaklanır. Gerçek normal ifade sözdizimi (yani, normal ifadeyi içeren dizeyi konsola yazdırırsanız) çift ters eğik çizgi gerektirmez.
nhahtdh

@NicolasRaoul Normal ifade dizgemi, yetkin bir IDE kullanarak gerçek java koduna kopyalayıp yapıştırırsanız, IDE kaçış eğik çizgilerini gerektiği gibi doğru şekilde biçimlendirir. Ancak benim Regex'im teknik ve sözdizimsel olarak doğrudur ve ana amaca, normal ifade kodu ile elde edilen sonuçlar arasındaki ilişkiyi göstermeye hizmet eder (çok özel bir örnek kullanarak) ... biraz hafiflet ...
Michael

44

Normal ()ifade ifadelerinin gruplandırılmasını sağlamak için parantez kullanılır.

Bu group(1), parantez içindeki dizeyi içerir, bu (.*)nedenle .*bu durumda

Ve group(0)tam eşleşen dizeyi içerir.

Daha fazla grubunuz varsa (okuyun (...)), sonraki dizinler (2, 3 vb.) İle gruplara konulacaktır.


2
Öyleyse, parantez eklemenin aslında grup oluşturmak için olduğu doğru mu?
P basak

3
Evet bunu söyleyebiliriz.
Michal Borek
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.