Java Normal İfade Yakalama Grupları


171

Bu kod bloğunu anlamaya çalışıyorum. İlkinde, ifadede aradığımız şey nedir?

Anladığım kadarıyla, herhangi bir karakter (0 veya daha fazla kez *), ardından 0 ile 9 arasında (bir veya daha fazla kez +) ve ardından herhangi bir karakter (0 veya daha fazla kez *).

Bu yürütüldüğünde sonuç:

Found value: This order was placed for QT3000! OK?
Found value: This order was placed for QT300
Found value: 0

Birisi lütfen benimle bunu yapabilir mi?

Yakalama gruplarını kullanmanın avantajı nedir?

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexTut3 {

    public static void main(String args[]) {
        String line = "This order was placed for QT3000! OK?"; 
        String pattern = "(.*)(\\d+)(.*)";

        // Create a Pattern object
        Pattern r = Pattern.compile(pattern);

        // Now create matcher object.
        Matcher m = r.matcher(line);

        if (m.find()) {
            System.out.println("Found value: " + m.group(0));
            System.out.println("Found value: " + m.group(1));
            System.out.println("Found value: " + m.group(2));
        } else {
            System.out.println("NO MATCH");
        }
    }

}

1
Yeni bir satır eklemek için satırın sonuna 2 boşluk yerleştirin. Markdown sözdizimi hakkında daha fazla bilgi: en.wikipedia.org/wiki/Markdown - Ayrıca bakınız: stackoverflow.com/editing-help
assylias

Yanıtlar:


250

Yaşadığınız sorun nicelik belirtici türüyle ilgili. İlk grubunuzda açgözlü bir nicelik belirteci kullanıyorsunuz (dizin 1 - dizin 0 bütünü temsil eder Pattern), yani olabildiğince eşleşir (ve herhangi bir karakter olduğundan, birçok karakterle eşleşir) olduğu gibi sonraki grupların koşullarını yerine getirmek için).

Kısacası, 1. grubunuz .*, bir sonraki grup bir \\d+şeyle eşleşebildiği sürece (bu durumda son rakam) herhangi bir şeyle eşleşir .

3. gruba göre, son rakamdan sonraki her şeyle eşleşecektir.

İlk grubunuzdaki isteksiz bir nicelik belirteciyle değiştirirseniz , beklediğiniz sonucu, yani 3000 parçasını .

1. gruptaki soru işaretini not edin .

String line = "This order was placed for QT3000! OK?";
Pattern pattern = Pattern.compile("(.*?)(\\d+)(.*)");
Matcher matcher = pattern.matcher(line);
while (matcher.find()) {
    System.out.println("group 1: " + matcher.group(1));
    System.out.println("group 2: " + matcher.group(2));
    System.out.println("group 3: " + matcher.group(3));
}

Çıktı:

group 1: This order was placed for QT
group 2: 3000
group 3: ! OK?

Java hakkında daha fazla bilgi Pattern burada .

Son olarak, yakalama grupları yuvarlak parantezlerle sınırlandırılır ve Patterngirdinizle eşleştirildikten sonra geri referansları (diğer şeylerin yanı sıra) kullanmak için çok kullanışlı bir yol sağlar .

Java'da 6 grup yalnızca sıralarına göre başvurulabilir (iç içe gruplara ve sıralamanın inceliğine dikkat edin).

Java 7'de adlandırılmış grupları kullanabildiğiniz için çok daha kolay.


Teşekkürler! Tüm grup bir veya daha fazla sayı ile temas edene kadar geri kalan açgözlü niceleyici tarafından tüketildiğinden, grup 2'nin 0 depolanmış olmasının nedeni. 0 bunu tatmin etti, böylece ifade başarılı oldu. Üçüncü grubu kafa karıştırıcı buluyorum, bu açgözlü niceleyici de tüm çizgiyi tüketiyor, ancak ondan önce olması gereken bir veya daha fazla sayıyı (\\ d +) bulana kadar geri çekiliyor mu?
Xivilai

@ Xivilai, cevabımda açıklamama ince ayar yapmama izin ver, sadece bir saniye.
Mena

Bu iyi bir açıklama. Bu yüzden isteksizler soldan başlar ve sadece asgari seviyeyi alırken, açgözlü ile, mümkün olduğu kadar (sağdan başlayarak), bu koşulu karşılamak için sadece son rakamdan önce durur. Üçüncü grup gerisini alır.
Xivilai

@Xivilai az çok. Bu durumda her zaman soldan başlar. Burada niceleyiciler hakkında daha fazla bilgi bulabilirsiniz.
Mena

2
Java 5/6 ile adlı yakalama gruplarını ile kullanabilirsiniz named-regexp.

16

Bu tamamen sorun değil.

  1. İlk grup ( m.group(0)) her zaman normal ifadenizin kapsadığı tüm alanı yakalar . Bu durumda, tüm dize.
  2. Düzenli ifadeler varsayılan olarak açgözlüdür, yani ilk grup normal ifadeyi ihlal etmeden mümkün olduğunca yakalar. (.*)(\\d+)(Senin regex ilk bölümü) kaplamaktadır ...QT300int birinci grubu ve 0ikinci.
  3. Değişikliği: Hızlı bir şekilde ilk grup olmayan açgözlü yaparak bu düzeltebilirsiniz (.*)için (.*?).

Açgözlü ve tembel hakkında daha fazla bilgi için bu siteyi kontrol edin .


4

Dokümandan:

Capturing groups</a> are indexed from left
 * to right, starting at one.  Group zero denotes the entire pattern, so
 * the expression m.group(0) is equivalent to m.group().

Yani grup 0'ı yakalamak tüm hattı gönderir.


3

Anlayışınız doğru. Ancak, üzerinden geçersek:

  • (.*) tüm ipi yutacak;
  • karakterleri geri vermesi gerekir, böylece (\\d+)satistifed edilir (bu yüzden 0yakalanır ve çekilmez 3000);
  • sonuncusu (.*)gerisini yakalar.

Ancak yazarın asıl amacının ne olduğundan emin değilim.

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.