Używam wyrażeń regularnych Java w Javie 1.6 (między innymi do analizowania danych liczbowych) i nie mogę znaleźć dokładnej definicji \b
(„granica słowa”). Zakładałem, że -12
będzie to „słowo całkowite” (dopasowane przez \b\-?\d+\b
), ale wygląda na to, że to nie działa. Byłbym wdzięczny za poznanie sposobów dopasowywania liczb oddzielonych spacjami.
Przykład:
Pattern pattern = Pattern.compile("\\s*\\b\\-?\\d+\\s*");
String plus = " 12 ";
System.out.println(""+pattern.matcher(plus).matches());
String minus = " -12 ";
System.out.println(""+pattern.matcher(minus).matches());
pattern = Pattern.compile("\\s*\\-?\\d+\\s*");
System.out.println(""+pattern.matcher(minus).matches());
To zwraca:
true
false
true
regex
word-boundary
peter.murray.rust
źródło
źródło
Odpowiedzi:
W większości dialektów wyrażeń regularnych granica słowa to pozycja między znakiem
\w
a\W
(znak niebędący słowem) lub na początku lub na końcu łańcucha, jeśli zaczyna się lub kończy (odpowiednio) znakiem słowa ([0-9A-Za-z_]
).Tak więc w ciągu
"-12"
pasowałoby przed 1 lub po 2. Myślnik nie jest znakiem słowa.źródło
\b
jest asercją o zerowej szerokości, która pasuje, jeśli występuje\w
po jednej stronie, a albo\W
po drugiej, albo pozycja jest początkiem lub końcem łańcucha.\w
jest arbitralnie definiowany jako znaki „identyfikujące” (alnum i podkreślenie), a nie jako coś szczególnie przydatnego w języku angielskim.\bhello\b
bez używania\b
(za pomocą\w
,\W
i inne)?(^|\W)hello($|\W)
z wyjątkiem tego, że nie przechwytuje żadnych znaków niebędących słowami przed i po, więc byłoby bardziej jak(^|(?<=\W))hello($|(?=\W))
(używając asercji lookahead / lookbehind).(?<!\w)hello(?!\w)
.Granica słowa może występować w jednej z trzech pozycji:
Znaki słów są alfanumeryczne; znak minus nie jest. Zaczerpnięte z samouczka Regex .
źródło
Podczas nauki wyrażeń regularnych naprawdę utknąłem w metaznaku, którym jest
\b
. Rzeczywiście, nie pojmowałem jego znaczenia, kiedy powtarzalnie zadawałem sobie pytanie „ co to jest, co to jest ”. Po kilku próbach korzystania ze strony internetowej zwracam uwagę na różowe pionowe kreski na każdym początku i na końcu słów. Rozumiem, że to dobrze w tamtym czasie. Teraz jest to dokładnie słowo (\w
) -graniczne .Mój pogląd jest po prostu niezmiernie zorientowany na zrozumienie. Logikę, która za tym stoi, należy zbadać na podstawie innych odpowiedzi.
źródło
Granica słowa to pozycja, która jest albo poprzedzona znakiem słowa i nie następuje po nim, albo następuje po niej znak słowa i nie jest poprzedzona jednym.
źródło
Mówię o tym, co
\b
granice -Style regex rzeczywiście są tutaj .Krótko mówiąc, jest to warunkowe . Ich zachowanie zależy od tego, co jest obok.
# same as using a \b before: (?(?=\w) (?<!\w) | (?<!\W) ) # same as using a \b after: (?(?<=\w) (?!\w) | (?!\W) )
Czasami nie tego chcesz. Zobacz moją drugą odpowiedź do rozwinięcia.
źródło
Chciałbym wyjaśnić, Alan Moore „s odpowiedź
Załóżmy, że mam ciąg „To jest c t, a ona wesome”, a ja powinien zastąpić wszystkie wystąpienia (S) literę „a” tylko wtedy, gdy ten list istnieje na „granicy słowa” , czyli litery wewnątrz słowa „kot” nie należy zastępować.
a
Więc wykonam regex (w Pythonie ) jako
re.sub("\ba","e", myString.strip())
// zastąpića
ze
więc wyjście będzie to
e
c na te
nd onae
wesomeźródło
Wpadłem na jeszcze gorszym problemem podczas wyszukiwania tekstu na słowa takie jak
.NET
,C++
,C#
, iC
. Można by pomyśleć, że programiści komputerowi wiedzieliby lepiej, niż nazywać język czymś, dla którego trudno jest pisać wyrażenia regularne.Tak czy inaczej, oto co się dowiedziałem (podsumowane głównie z http://www.regular-expressions.info , która jest świetną stroną): W większości odmian wyrażenia regularnego znaki, które są dopasowywane przez klasę znaków krótkiej ręki
\w
to znaki, które są traktowane jako znaki słowa według granic słów. Java jest wyjątkiem. Java obsługuje Unicode dla,\b
ale nie dla\w
. (Jestem pewien, że wtedy był ku temu dobry powód).\w
Oznacza „charakteru słowa”. Zawsze pasuje do znaków ASCII[A-Za-z0-9_]
. Zwróć uwagę na podkreślenie i cyfry (ale nie myślnik!). W większości wersji obsługujących Unicode\w
zawiera wiele znaków z innych skryptów. Istnieje wiele niespójności co do tego, które postacie są faktycznie uwzględnione. Zwykle uwzględniane są litery i cyfry ze skryptów alfabetycznych i ideogramów. Interpunkcja łącznika, inna niż podkreślenie i symbole numeryczne, które nie są cyframi, może, ale nie musi, zostać uwzględniona. Schemat XML i XPath zawierają nawet wszystkie symbole w\w
. Ale Java, JavaScript i PCRE dopasowują tylko znaki ASCII z\w
.Dlatego Java regex wyszukuje
C++
,C#
lub.NET
(nawet jeśli pamiętać, aby uciec od okresu i plusy) przykręcone są przez\b
.Uwaga: nie jestem pewien, co zrobić z błędami w tekście, na przykład gdy ktoś nie wstawia spacji po kropce na końcu zdania. Pozwoliłem na to, ale nie jestem pewien, czy koniecznie jest to właściwe postępowanie.
W każdym razie, w Javie, jeśli szukasz tekstu dla tych dziwnie nazwanych języków, musisz zamienić na
\b
przed i po białych znakach i znakach interpunkcyjnych. Na przykład:public static String grep(String regexp, String multiLineStringToSearch) { String result = ""; String[] lines = multiLineStringToSearch.split("\\n"); Pattern pattern = Pattern.compile(regexp); for (String line : lines) { Matcher matcher = pattern.matcher(line); if (matcher.find()) { result = result + "\n" + line; } } return result.trim(); }
Następnie w teście lub funkcji głównej:
String beforeWord = "(\\s|\\.|\\,|\\!|\\?|\\(|\\)|\\'|\\\"|^)"; String afterWord = "(\\s|\\.|\\,|\\!|\\?|\\(|\\)|\\'|\\\"|$)"; text = "Programming in C, (C++) C#, Java, and .NET."; System.out.println("text="+text); // Here is where Java word boundaries do not work correctly on "cutesy" computer language names. System.out.println("Bad word boundary can't find because of Java: grep with word boundary for .NET="+ grep("\\b\\.NET\\b", text)); System.out.println("Should find: grep exactly for .NET="+ grep(beforeWord+"\\.NET"+afterWord, text)); System.out.println("Bad word boundary can't find because of Java: grep with word boundary for C#="+ grep("\\bC#\\b", text)); System.out.println("Should find: grep exactly for C#="+ grep("C#"+afterWord, text)); System.out.println("Bad word boundary can't find because of Java:grep with word boundary for C++="+ grep("\\bC\\+\\+\\b", text)); System.out.println("Should find: grep exactly for C++="+ grep(beforeWord+"C\\+\\+"+afterWord, text)); System.out.println("Should find: grep with word boundary for Java="+ grep("\\bJava\\b", text)); System.out.println("Should find: grep for case-insensitive java="+ grep("?i)\\bjava\\b", text)); System.out.println("Should find: grep with word boundary for C="+ grep("\\bC\\b", text)); // Works Ok for this example, but see below // Because of the stupid too-short cutsey name, searches find stuff it shouldn't. text = "Worked on C&O (Chesapeake and Ohio) Canal when I was younger; more recently developed in Lisp."; System.out.println("text="+text); System.out.println("Bad word boundary because of C name: grep with word boundary for C="+ grep("\\bC\\b", text)); System.out.println("Should be blank: grep exactly for C="+ grep(beforeWord+"C"+afterWord, text)); // Make sure the first and last cases work OK. text = "C is a language that should have been named differently."; System.out.println("text="+text); System.out.println("grep exactly for C="+ grep(beforeWord+"C"+afterWord, text)); text = "One language that should have been named differently is C"; System.out.println("text="+text); System.out.println("grep exactly for C="+ grep(beforeWord+"C"+afterWord, text)); //Make sure we don't get false positives text = "The letter 'c' can be hard as in Cat, or soft as in Cindy. Computer languages should not require disambiguation (e.g. Ruby, Python vs. Fortran, Hadoop)"; System.out.println("text="+text); System.out.println("Should be blank: grep exactly for C="+ grep(beforeWord+"C"+afterWord, text));
PS Moje podziękowania dla http://regexpal.com/, bez którego świat regexów byłby bardzo nieszczęśliwy!
źródło
C#
ale teraz jest to wyraźniejszeZapoznaj się z dokumentacją dotyczącą warunków brzegowych:
http://java.sun.com/docs/books/tutorial/essential/regex/bounds.html
Sprawdź tę próbkę:
public static void main(final String[] args) { String x = "I found the value -12 in my string."; System.err.println(Arrays.toString(x.split("\\b-?\\d+\\b"))); }
Podczas drukowania zwróć uwagę, że wynik jest następujący:
[Znalazłem wartość - w moim ciągu.]
Oznacza to, że znak „-” nie jest odbierany jako znajdujący się na granicy słowa, ponieważ nie jest uważany za znak słowa. Wygląda na to, że @brianary trochę mnie pobił, więc dostaje pozytywny głos.
źródło
Granica słowa \ b jest używana, gdy jedno słowo powinno być znakiem słowa, a drugie znakiem innym niż słowo. Wyrażenie regularne dla liczby ujemnej powinno wynosić
--?\b\d+\b
sprawdź działające DEMO
źródło
Uważam, że twój problem wynika z faktu, że
-
nie jest to słowo charakter. W ten sposób granica słowa będzie pasować po znaku-
, więc nie będzie go przechwytywać. Granice wyrazów pasują do znaków przed pierwszym i po ostatnim słowie w ciągu, a także w każdym miejscu, w którym przed nim znajduje się znak słowa lub znak niebędący słowem, a po nim jest odwrotnie. Zauważ również, że granica słowa jest dopasowaniem o zerowej szerokości.Jedną z możliwych alternatyw jest
(?:(?:^|\s)-?)\d+\b
Spowoduje to dopasowanie wszystkich liczb zaczynających się od spacji i opcjonalnego myślnika, a kończących się na granicy słowa. Dopasuje również liczbę zaczynającą się na początku ciągu.
źródło
Myślę, że to granica (tj. Znak następujący) ostatniego dopasowania lub początek lub koniec ciągu.
źródło
\G
: dopasowuje początek łańcucha (jak\A
) przy pierwszej próbie dopasowania; po tym dopasowuje pozycję, na której zakończył się poprzedni mecz.kiedy używasz
\\b(\\w+)+\\b
tego słowa, oznacza to dokładne dopasowanie do słowa zawierającego tylko znaki słowa([a-zA-Z0-9])
w twoim przypadku np. ustawienie
\\b
na początku wyrażenia regularnego zaakceptuje-12
(ze spacją), ale znowu nie zaakceptuje-12
(bez spacji)w celach informacyjnych na poparcie moich słów: https://docs.oracle.com/javase/tutorial/essential/regex/bounds.html
źródło
Odniesienie: Opanowanie wyrażeń regularnych (Jeffrey EF Friedl) - O'Reilly
\ b jest równoważne
(?<!\w)(?=\w)|(?<=\w)(?!\w)
źródło