Wszystkie nakładające się podciągi pasujące do wyrażenia regularnego java
Czy istnieje metoda API, która zwraca wszystkie (prawdopodobnie nakładające się) podciągi, które pasują do wyrażenia regularnego?
Na przykład mam ciąg tekstowy:String t = 04/31 412-555-1235;
i mam wzór:Pattern p = new Pattern("\\d\\d+");
pasujący do ciągów dwóch lub więcej znaków.
Mecze, które dostaję, to: 04, 31, 412, 555, 1235.
Jak uzyskać nakładające się mecze?
Chcę, aby kod powrócił: 04, 31, 41, 412, 12, 55, 555, 55, 12, 123, 1235, 23, 235, 35.
Teoretycznie powinno być to możliwe - jest oczywisteO(n^2)
algorytm wyliczający i sprawdzający wszystkie podciągi względem wzorca.
EDYTOWAĆ
Zamiast wyliczać wszystkie podciągi, bezpieczniej jest użyćregion(int start, int end)
metoda wMatcher
. Sprawdzanie wzorca w oddzielnym, wyodrębnionym podciągu może zmienić wynik dopasowania (np. Jeśli na początku / końcu wzorca znajduje się grupa nie przechwytująca lub sprawdzanie granicy wyrazu).
EDYCJA 2
Właściwie nie jest jasne, czyregion()
robi to, czego oczekujesz dla dopasowań o zerowej szerokości. Specyfikacja jest niejasna, a eksperymenty przynoszą rozczarowujące wyniki.
Na przykład:
String line = "xx90xx";
String pat = "\\b90\\b";
System.out.println(Pattern.compile(pat).matcher(line).find()); // prints false
for (int i = 0; i < line.length(); ++i) {
for (int j = i + 1; j <= line.length(); ++j) {
Matcher m = Pattern.compile(pat).matcher(line).region(i, j);
if (m.find() && m.group().size == (j - i)) {
System.out.println(m.group() + " (" + i + ", " + j + ")"); // prints 90 (2, 4)
}
}
}
Nie jestem pewien, jakie jest najbardziej eleganckie rozwiązanie. Jednym z podejść byłoby pobranie podciągówline
i zaznacz odpowiednimi znakami granicznymi przed sprawdzeniem, czypat
mecze.
EDYCJA 3
Oto pełne rozwiązanie, które wymyśliłem. Może obsługiwać wzory, granice itp. O zerowej szerokości w oryginalnym wyrażeniu regularnym. Przegląda wszystkie podciągi ciągu tekstowego i sprawdza, czy wyrażenie regularne pasuje tylko do określonej pozycji, wypełniając wzorzec odpowiednią liczbą symboli wieloznacznych na początku i na końcu. Wydaje się, że działa w przypadkach, które wypróbowałem - chociaż nie przeprowadziłem dokładnych testów. Z pewnością jest mniej wydajny niż mógłby być.
public static void allMatches(String text, String regex)
{
for (int i = 0; i < text.length(); ++i) {
for (int j = i + 1; j <= text.length(); ++j) {
String positionSpecificPattern = "((?<=^.{"+i+"})("+regex+")(?=.{"+(text.length() - j)+"}$))";
Matcher m = Pattern.compile(positionSpecificPattern).matcher(text);
if (m.find())
{
System.out.println("Match found: \"" + (m.group()) + "\" at position [" + i + ", " + j + ")");
}
}
}
}
EDYCJA 4
Oto lepszy sposób:https://stackoverflow.com/a/11372670/244526
EDYTUJ 5
TheJRegex biblioteka obsługuje wyszukiwanie wszystkich nakładających się podciągów pasujących do wyrażenia regularnego java (chociaż wydaje się, że nie zostało zaktualizowane za jakiś czas). W szczególnościdokumentacja dotycząca wyszukiwania bez łamania określa:
Używając wyszukiwania bez łamania, możesz znaleźć wszystkie możliwe występy wzorca, w tym przecinające się lub zagnieżdżone. Osiąga się to za pomocą metody Matchera continue () zamiast find ()