Normal ifade kullanarak bir alt dize nasıl ayıklanır


382

İçinde iki tek tırnak, 'karakter olan bir dize var . Tek tırnak arasında istediğim veri var.

Aşağıdaki metinden "istediğim verileri" ayıklamak için nasıl normal ifade yazabilirim?

mydata = "some string with 'the data i want' inside";

Yanıtlar:


569

Tek tırnak işaretleri arasında yer almak istediğinizi varsayarsak, bu normal ifadeyi aşağıdakilerle birlikte kullanın Matcher:

"'(.*?)'"

Misal:

String mydata = "some string with 'the data i want' inside";
Pattern pattern = Pattern.compile("'(.*?)'");
Matcher matcher = pattern.matcher(mydata);
if (matcher.find())
{
    System.out.println(matcher.group(1));
}

Sonuç:

istediğim veriler

12
lanet olsun ... her zaman açgözlü olmayan değiştiriciyi unutuyorum :(
Mihai Toader

33
birden fazla olayı beklediğinizde "if" ifadesini "while" ile değiştirin
OneWorld

14
Bu kod örneğinin çalışması için matcher.find () işlevinin gerekli olduğunu unutmayın. bu yöntemin çağrılmaması, matcher.group (1) çağrıldığında "Eşleşme bulunamadı" özel durumu ile sonuçlanır.
rexford

25
@mFontoura grubu (0) dış eşleşmenin tamamını döndürür ''. grup (1) '' arasında '' olmayanları kendisi döndürür.
tagy22

6
@Larry bu geç bir cevap, ama? bu durumda açgözlü olmayan bir değiştiricidir, böylece bunun için this 'is' my 'data' with quoteserken durur ve ismümkün olduğunca çok karakter eşleştirmek yerine geri döner is' my 'datave varsayılan davranış olan geri döner .
Timekiller

68

Bunun için normal ifadeye ihtiyacınız yok.

Projenize apache commons lang ekleyin ( http://commons.apache.org/proper/commons-lang/ ), ardından şunu kullanın:

String dataYouWant = StringUtils.substringBetween(mydata, "'");

12
Yazılımınızın nasıl dağıtılacağını hesaba katmalısınız. Web başlangıcı gibi bir şeyse, yalnızca bu işlevselliği kullanmak için Apache ortaklarını eklemek akıllıca değildir. Ama belki de değil. Ayrıca Apache müşterilerinin sunabileceği çok şey var. Regex'i bilmek zor olsa bile, ne zaman kullanılacağına dikkat etmelisiniz. Normal ifade okumak, yazmak ve hata ayıklamak gerçekten zor olabilir. Bunu kullanarak bazı bağlamlar göz önüne alındığında daha iyi bir çözüm olabilir.
Beothorn

3
Bazen StringUtils zaten orada, bu durumlarda bu çözüm çok daha temiz ve okunabilir.
Gábor Nagy

7
Onun gibi yılda sadece bir kez seyahat ederken 5 mil seyahat için bir araba satın almak gibi.
prayagupd

Alt dize belirli bir dize veya değer ararken regex bir biçim arar. Gittikçe daha dinamik. Özel bir değer yerine bir model arıyorsanız normal ifadeye ihtiyacınız vardır.
burakhan alkan

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

public class Test {
    public static void main(String[] args) {
        Pattern pattern = Pattern.compile(".*'([^']*)'.*");
        String mydata = "some string with 'the data i want' inside";

        Matcher matcher = pattern.matcher(mydata);
        if(matcher.matches()) {
            System.out.println(matcher.group(1));
        }

    }
}

2
System.out.println (matcher.group (0)); <--- Sıfır tabanlı endeks
nclord

4
No. grubu (0) özel bir anlama sahiptir, yakalama grupları indeks grubu (1) 'de başlar (yani cevapta grup (1) doğrudur). "Yakalama grupları soldan sağa, birinden başlayarak dizine eklenir. Grup sıfır tüm kalıbı belirtir" - Kaynak: docs.oracle.com/javase/8/docs/api/java/util/regex/…
Apriori

12

Bunun için basit bir astar var:

String target = myData.replaceAll("[^']*(?:'(.*?)')?.*", "$1");

Eşleşen grubu isteğe bağlı hale getirerek, bu durumda bir boşluk döndürülerek tırnak bulunamaması da sağlanır.

Canlı demoya bakın .


10

Ayrıca, birden fazla alıntılanan dizeyle kolayca ilgilenen normal ifadesiz bir çözüm olan Scala'yı işaretlediniz:

val text = "some string with 'the data i want' inside 'and even more data'"
text.split("'").zipWithIndex.filter(_._2 % 2 != 0).map(_._1)

res: Array[java.lang.String] = Array(the data i want, and even more data)

4
Çok okunabilir bir çözüm, bu yüzden insanlar inanıyorum scala seviyorum inanıyorum :)
prayagupd

3
Neden .split('\'').get(2)Java'da böyle bir şey olmasın ? Bence bu okunabilir bir çözüm olduğunu düşünüyorsanız bir beyin taraması yapmanız gerekebilir - birisi bana bir kod golf yapmaya çalışıyor gibi görünüyor.
ArtOfWarfare

7
String dataIWant = mydata.replaceFirst(".*'(.*?)'.*", "$1");

4

javascript'teki gibi:

mydata.match(/'([^']+)'/)[1]

gerçek ifade: /'([^']+)'/

açgözlü olmayan değiştiriciyi kullanırsanız (başka bir gönderiye göre) şöyle:

mydata.match(/'(.*?)'/)[1]

daha temiz.


2

Scala'da,

val ticks = "'([^']*)'".r

ticks findFirstIn mydata match {
    case Some(ticks(inside)) => println(inside)
    case _ => println("nothing")
}

for (ticks(inside) <- ticks findAllIn mydata) println(inside) // multiple matches

val Some(ticks(inside)) = ticks findFirstIn mydata // may throw exception

val ticks = ".*'([^']*)'.*".r    
val ticks(inside) = mydata // safe, shorter, only gets the first set of ticks


1

Apache Commons Lang, java.lang API için, özellikle Dize düzenleme yöntemleri için bir dizi yardımcı yardımcı program sağlar. Sizin durumunuzda, başlangıç ​​ve bitiş alt dizeleri aynıdır, bu nedenle aşağıdaki işlevi çağırmanız yeterlidir.

StringUtils.substringBetween(String str, String tag)

Aynı Dize'nin iki örneği arasında yuvalanan Dizeyi alır .

Başlangıç ​​ve bitiş alt dizeleri farklıysa, aşağıdaki aşırı yüklenmiş yöntemi kullanın.

StringUtils.substringBetween(String str, String open, String close)

İki dize arasında yuvalanmış dize alır.

Eşleşen alt dizelerin tüm örneklerini istiyorsanız,

StringUtils.substringsBetween(String str, String open, String close)

Dizede eşleşen tüm alt dizeleri döndürerek bir başlangıç ​​ve bitiş etiketiyle ayrılmış alt dizeleri arar .

Söz konusu örnekte eşleşen alt dizenin tüm örneklerini almak için

String[] results = StringUtils.substringsBetween(mydata, "'", "'");

0

Eğer kullanırsanız dizideki tüm eşleşmeler alt dizesini saklamak için while döngüsü kullanabilirsiniz

if (matcher.find()) { System.out.println(matcher.group(1)); }

eşleşmeler alt dize alırsınız, böylece tüm eşleşmeler alt dize almak için bunu kullanabilirsiniz

Matcher m = Pattern.compile("[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+").matcher(text);
   // Matcher  mat = pattern.matcher(text);
    ArrayList<String>matchesEmail = new ArrayList<>();
        while (m.find()){
            String s = m.group();
            if(!matchesEmail.contains(s))
                matchesEmail.add(s);
        }

    Log.d(TAG, "emails: "+matchesEmail);

0

pom.xml'nize apache.commons bağımlılığını ekleyin

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-io</artifactId>
    <version>1.3.2</version>
</dependency>

Ve aşağıdaki kod çalışır.

StringUtils.substringBetween(String mydata, String "'", String "'")

0

Bazı grup (1) benim için çalışmadı. URL sürümünü bulmak için grup (0) kullandım.

Pattern urlVersionPattern = Pattern.compile("\\/v[0-9][a-z]{0,1}\\/");
Matcher m = urlVersionPattern.matcher(url);
if (m.find()) { 
    return StringUtils.substringBetween(m.group(0), "/", "/");
}
return "v0";
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.