Jak wyodrębnić podciąg za pomocą wyrażenia regularnego

382

Mam ciąg znaków, który zawiera dwa pojedyncze cudzysłowy - 'znak. Pomiędzy pojedynczymi cudzysłowami znajdują się dane, które chcę.

Jak napisać wyrażenie regularne, aby wyodrębnić „dane, które chcę” z następującego tekstu?

mydata = "some string with 'the data i want' inside";
asdasd
źródło

Odpowiedzi:

569

Zakładając, że chcesz część między pojedynczymi cudzysłowami, użyj tego wyrażenia regularnego z Matcher:

"'(.*?)'"

Przykład:

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

Wynik:

dane, które chcę
Mark Byers
źródło
12
cholera .. zawsze zapominam o nie chciwym modyfikatorze :(
Mihai Toader
33
zamień „if” na „chwilę”, jeśli spodziewane są więcej niż jedno wystąpienie
OneWorld,
14
pamiętaj, że matcher.find () jest potrzebny do działania tego przykładu kodu. niepowodzenie wywołania tej metody spowoduje wyjątek „Nie znaleziono dopasowania” po wywołaniu matcher.group (1).
rexford
25
Grupa @ mFontoura (0) zwróci pełne dopasowanie z zewnętrznym „”. grupa (1) zwraca to, co jest pomiędzy „” bez „”.
tagy22
6
@ Larry to późna odpowiedź, ale? w tym przypadku nie jest chciwy modyfikator, tak że this 'is' my 'data' with quoteszatrzyma się wcześnie i wróci iszamiast dopasowywać jak najwięcej znaków i zwróci is' my 'data, co jest zachowaniem domyślnym.
Timekiller
68

Nie potrzebujesz do tego wyrażenia regularnego.

Dodaj apache commons lang do swojego projektu ( http://commons.apache.org/proper/commons-lang/ ), a następnie użyj:

String dataYouWant = StringUtils.substringBetween(mydata, "'");
Beothorn
źródło
12
Musisz wziąć pod uwagę sposób dystrybucji oprogramowania. Jeśli jest to coś w rodzaju webstartu, nie jest mądrze dodawać wspólne Apache tylko w celu korzystania z tej jednej funkcji. Ale może nie jest. Oprócz tego Apache ma wiele więcej do zaoferowania. Nawet jeśli dobrze jest znać regex, musisz uważać, kiedy go użyć. Regex może być bardzo trudny do odczytania, napisania i debugowania. Biorąc pod uwagę kontekst, użycie tego może być lepszym rozwiązaniem.
Beothorn,
3
Czasami StringUtils już tam jest, w takich przypadkach to rozwiązanie jest znacznie czystsze i czytelniejsze.
Gábor Nagy
7
To jak kupowanie samochodu na 5 mil (gdy podróżujesz tylko raz w roku).
prayagupd
Podczas gdy substring szuka określonego ciągu lub wartości, regex szuka formatu. Jest coraz bardziej dynamiczny. Potrzebujesz wyrażenia regularnego, jeśli szukasz wzoru zamiast specjalnej wartości.
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));
        }

    }
}
Sean McEligot
źródło
2
System.out.println (matcher.group (0)); <--- Indeks
zerowy
4
Nie. Grupa (0) ma specjalne znaczenie, przechwytywanie grup rozpoczyna się od grupy indeksów (1) (tj. Grupa (1) ma poprawną odpowiedź). „Grupy przechwytywania są indeksowane od lewej do prawej, zaczynając od 1. Grupa zero oznacza cały wzorzec” - Źródło: docs.oracle.com/javase/8/docs/api/java/util/regex/…
Apriori
12

Jest w tym prosty prosty linijka:

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

Jeśli opcjonalna grupa dopasowywania będzie opcjonalna, będzie to również uwzględniać cytaty, których nie można znaleźć, zwracając w tym przypadku spację.

Zobacz demo na żywo .

Czeski
źródło
10

Ponieważ zaznaczyłeś także Scalę, rozwiązanie bez wyrażenia regularnego, które łatwo radzi sobie z wieloma cytowanymi ciągami:

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)
Debilski
źródło
4
Tak czytelne rozwiązanie, dlatego ludzie uwielbiają
Scalę,
3
Dlaczego nie tylko .split('\'').get(2)lub coś w tym zakresie w Javie? Myślę, że możesz potrzebować skanu mózgu, jeśli uważasz, że to czytelne rozwiązanie - wygląda na to, że ktoś próbował mi zrobić golfa.
ArtOfWarfare
7
String dataIWant = mydata.replaceFirst(".*'(.*?)'.*", "$1");
ZehnVon12
źródło
4

jak w javascript:

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

rzeczywiste wyrażenie regularne to: /'([^']+)'/

jeśli używasz nie chciwego modyfikatora (jak w innym poście), wygląda to tak:

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

to jest czystsze.

Mihai Toader
źródło
2

W Scali

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
Daniel C. Sobral
źródło
1

Apache Commons Lang udostępnia wiele narzędzi pomocniczych dla interfejsu API java.lang, w szczególności metod manipulacji ciągami. W twoim przypadku początkowe i końcowe podciągi są takie same, więc po prostu wywołaj następującą funkcję.

StringUtils.substringBetween(String str, String tag)

Pobiera łańcuch, który jest zagnieżdżony między dwoma instancjami tego samego łańcucha .

Jeśli początkowe i końcowe podciągi są różne, użyj następującej metody przeciążenia.

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

Pobiera ciąg zagnieżdżony między dwoma ciągami.

Jeśli chcesz wszystkie wystąpienia pasujących podciągów, użyj:

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

Przeszukuje ciąg pod kątem podciągów rozdzielonych znacznikiem początkowym i końcowym, zwracając wszystkie pasujące podciągi w tablicy .

Na przykład, aby uzyskać wszystkie wystąpienia pasującego podciągu

String[] results = StringUtils.substringsBetween(mydata, "'", "'");
Memin
źródło
0

możesz użyć tego używam pętli while do przechowywania wszystkich pasujących podciągów w tablicy, jeśli używasz

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

dostaniesz podłańcuch dopasowań, dzięki czemu możesz użyć tego, aby uzyskać podłańcuch wszystkich dopasowań

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);
Nouh Mohamed
źródło
0

dodaj zależność apache.commons od pom.xml

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

I poniżej działa kod.

StringUtils.substringBetween(String mydata, String "'", String "'")
Ganesh
źródło
0

Trochę jak grupa (1) nie działała dla mnie. Użyłem grupy (0), aby znaleźć wersję adresu URL.

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";
Arindam
źródło