Próbuję dopasować tekst wielowierszowy za pomocą języka Java. Kiedy używam Pattern
klasy z Pattern.MULTILINE
modyfikatorem, jestem w stanie dopasować, ale nie jestem w stanie tego zrobić z(?m).
Wydaje się, że ten sam wzorzec zi (?m)
używania String.matches
nie działa.
Jestem pewien, że czegoś mi brakuje, ale nie mam pojęcia, co. Nie jestem dobry w wyrażeniach regularnych.
Właśnie tego próbowałem
String test = "User Comments: This is \t a\ta \n test \n\n message \n";
String pattern1 = "User Comments: (\\W)*(\\S)*";
Pattern p = Pattern.compile(pattern1, Pattern.MULTILINE);
System.out.println(p.matcher(test).find()); //true
String pattern2 = "(?m)User Comments: (\\W)*(\\S)*";
System.out.println(test.matches(pattern2)); //false - why?
(?s)User Comments:\s*(.*)
. Z odpowiedzi @Amarghosh mam wzórUser Comments: [\\s\\S]*
. Czy jest wśród nich lepszy lub zalecany sposób, czy też są to tylko dwa różne sposoby robienia tego samego?[\s\S]
jest nieco bardziej wyraźny („dopasuj dowolny znak, który jest albo białą, albo nie-białą spacją”),.
jest łatwiejszy do odczytania, ale musisz poszukać modyfikatora(?s)
lubDOTALL
, aby dowiedzieć się, czy nowe linie są uwzględnione, czy nie. Wolałbym.
zPattern.DOTALL
ustawioną flagą (jest to łatwiejsze do odczytania i zapamiętania niż(?s)
moim zdaniem. Powinieneś używać tego, z czym czujesz się najbardziej komfortowo..*
zeDOTALL
jest bardziej czytelny. Użyłem drugiego, aby pokazać, że problem tkwi w różnicach między str.matches i matcher.find, a nie w flagach. +1.*
zPattern.DOTALL
, ale będę musiał iść z (?), Ponieważ muszę używaćString.matches
.Nie ma to nic wspólnego z flagą MULTILINE; to, co widzisz, to różnica między metodami
find()
imatches()
.find()
powiedzie się, jeśli dopasowanie można znaleźć w dowolnym miejscu w ciągu docelowym , podczas gdymatches()
oczekuje, że wyrażenie regularne będzie pasować do całego ciągu .Co więcej,
MULTILINE
nie oznacza tego, co myślisz, że robi. Wiele osób wydaje się dochodzić do wniosku, że musisz użyć tej flagi, jeśli twój docelowy ciąg zawiera znaki nowej linii - to znaczy, jeśli zawiera wiele linii logicznych. Widziałem tutaj kilka odpowiedzi na SO w tym celu, ale w rzeczywistości wszystko, co robi ta flaga, to zmienia zachowanie kotwic,^
i$
.Zwykle
^
dopasowuje sam początek ciągu docelowego i$
dopasowuje sam koniec (lub przed nową linią na końcu, ale na razie zostawimy to na boku). Ale jeśli ciąg zawiera znaki nowej linii, możesz wybrać opcję^
i$
dopasować na początku i na końcu dowolnej linii logicznej, a nie tylko na początku i na końcu całego ciągu, ustawiając flagę MULTILINE.Więc zapomnij o tym, co
MULTILINE
oznacza i po prostu pamiętaj, co robi : zmienia zachowanie kotwic^
i$
.DOTALL
tryb początkowo był nazywany „jednoliniowym” (i nadal występuje w niektórych wersjach, w tym w Perlu i .NET) i zawsze powodował podobne zamieszanie. Na szczęście twórcy Javy wybrali w tym przypadku bardziej opisową nazwę, ale nie było rozsądnej alternatywy dla trybu „wielowierszowego”.W Perlu, gdzie całe to szaleństwo się zaczęło, przyznali się do błędu i pozbyli się trybu „wielowierszowego” i „pojedynczej linii” w wyrażeniach regularnych Perl 6. Za dwadzieścia lat może reszta świata pójdzie w ich ślady.
źródło
str.matches(regex)
zachowuje się tak, jakbyPattern.matches(regex, str)
próbował dopasować całą sekwencję wejściową do wzorca i zwracaNatomiast
matcher.find()
próbuje znaleźć następny podciąg sekwencji wejściowej, który pasuje do wzorca i zwracaTak więc problem dotyczy wyrażenia regularnego. Spróbuj wykonać następujące czynności.
Krótko mówiąc,
(\\W)*(\\S)*
część w twoim pierwszym wyrażeniu regularnym dopasowuje pusty ciąg, ponieważ*
oznacza zero lub więcej wystąpień, a prawdziwy dopasowany ciąg to,User Comments:
a nie cały ciąg, jak można się spodziewać. Drugi zawodzi, ponieważ próbuje dopasować cały ciąg, ale nie może\\W
dopasować znaku innego niż słowo, tj.[^a-zA-Z0-9_]
A pierwszy znak toT
znak słowa.źródło
User Comments: [\\s\\S]*
i to zadziałało. (dzięki!) Z odpowiedzi @Tim mam wzorzecUser Comments:(.*)
, to również jest w porządku. Czy jest wśród nich zalecany lub lepszy sposób, czy są to tylko dwa sposoby na zrobienie tego samego?(.*)
wraz zDOTALL
flagą jest bardziej oczywiste / czytelne niż([\\s\\S]*)
Flaga multilinii mówi regex, aby dopasował wzorzec do każdej linii, a nie do całego ciągu. Do twoich celów wystarczy wieloznaczna karta.
źródło