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";

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ę

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, "'");

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

    }
}

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 .


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)

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


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.


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


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, "'", "'");

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

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 "'")

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";
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.