Một ranh giới từ trong regex là gì?


137

Tôi đang sử dụng các biểu thức Java trong Java 1.6 (để phân tích đầu ra số, trong số các mục đích khác) và không thể tìm thấy một định nghĩa chính xác về \b("ranh giới từ"). Tôi đã giả định rằng đó -12sẽ là một "từ nguyên" (khớp với \b\-?\d+\b) nhưng có vẻ như điều này không hoạt động. Tôi rất biết ơn khi biết cách kết hợp các số được phân tách bằng dấu cách.

Thí dụ:

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

Điều này trả về:

true
false
true

Bạn có thể gửi một ví dụ nhỏ với đầu vào và đầu ra dự kiến?
Mã Brent viết

Ví dụ Mẫu hoa văn = Pattern.compile ("\\ s * \\ b \\ -? \\ d + \\ s *"); Chuỗi cộng = "12"; System.out.println ("" + pattern.matcher (cộng) .matches ()); Chuỗi trừ = "-12"; System.out.println ("" + pattern.matcher (trừ) .matches ()); mẫu = Pattern.compile ("\\ s * \\ -? \\ d + \\ s *"); System.out.println ("" + pattern.matcher (trừ) .matches ()); cho: đúng sai đúng
peter.m bồ.rust

Câu trả lời:


97

Một ranh giới từ, trong hầu hết các phương ngữ regex, là một vị trí giữa \w\W(char không phải từ), hoặc ở đầu hoặc cuối chuỗi nếu nó bắt đầu hoặc kết thúc (tương ứng) với một ký tự từ ( [0-9A-Za-z_]).

Vì vậy, trong chuỗi "-12", nó sẽ khớp trước 1 hoặc sau 2. Dấu gạch ngang không phải là ký tự từ.


35
Correctamundo. \blà một xác nhận có độ rộng bằng 0 khớp với nếu có \wở một bên và ở \Wbên kia hoặc vị trí bắt đầu hoặc kết thúc chuỗi. \wđược định nghĩa tùy ý là các ký tự "định danh" (alnums và gạch dưới), không phải là bất cứ điều gì đặc biệt hữu ích cho tiếng Anh.
hobbs

Đúng 100%. Xin lỗi vì không chỉ bình luận về bạn. Tôi nhấn gửi trước khi tôi thấy câu trả lời của bạn.
Mã Brent viết

5
vì lợi ích của sự hiểu biết, là nó có thể viết lại regex \bhello\bmà không sử dụng \b(sử dụng \w, \Wvà khác)?
David Portabella

5
Sắp xếp :, (^|\W)hello($|\W)ngoại trừ việc nó sẽ không bắt được bất kỳ ký tự không phải từ nào trước và sau, vì vậy nó sẽ giống như (^|(?<=\W))hello($|(?=\W))(sử dụng các xác nhận lookahead / lookbehind).
brianary

6
@brianary Đơn giản hơn một chút : (?<!\w)hello(?!\w).
David Knipe

28

Một ranh giới từ có thể xảy ra ở một trong ba vị trí:

  1. Trước ký tự đầu tiên trong chuỗi, nếu ký tự đầu tiên là ký tự từ.
  2. Sau ký tự cuối cùng trong chuỗi, nếu ký tự cuối cùng là ký tự từ.
  3. Giữa hai ký tự trong chuỗi, trong đó một ký tự là từ và ký tự còn lại không phải là ký tự từ.

Các ký tự từ là số alpha; một dấu trừ là không. Lấy từ hướng dẫn Regex .


21

Trong quá trình học biểu hiện chính quy, tôi thực sự bị mắc kẹt trong metacharacter \b. Tôi thực sự đã không hiểu ý nghĩa của nó trong khi tôi đang tự hỏi mình " nó là gì, nó là gì " lặp đi lặp lại. Sau một số nỗ lực bằng cách sử dụng trang web , tôi xem các dấu gạch ngang màu hồng ở mỗi đầu từ và cuối từ. Tôi hiểu ý nghĩa của nó lúc đó Bây giờ chính xác là từ ( \w) -aryary .

Quan điểm của tôi chỉ đơn thuần là vô cùng định hướng theo định hướng. Logic đằng sau của nó nên được xem xét từ một câu trả lời khác.

nhập mô tả hình ảnh ở đây


3
Một trang web rất tốt để hiểu ranh giới từ là gì và cách các trận đấu đang diễn ra
so với

2
Bài đăng này xứng đáng tín dụng để hiển thị thay vì nói. Một bức tranh đáng giá ngàn lời nói.
M_M

13

Ranh giới từ là một vị trí được đặt trước một ký tự từ và không được theo sau bởi một ký tự hoặc theo sau bởi một ký tự từ và không đi trước một ký tự.


8

Tôi nói về \branh giới regex kiểu gì thực sự ở đây .

Câu chuyện ngắn là chúng có điều kiện . Hành vi của họ phụ thuộc vào những gì họ bên cạnh.

# same as using a \b before:
(?(?=\w) (?<!\w)  | (?<!\W) )

# same as using a \b after:
(?(?<=\w) (?!\w)  | (?!\W)  )

Đôi khi đó không phải là điều bạn muốn. Xem câu trả lời khác của tôi cho công phu.


7

Tôi muốn giải thích câu trả lời của Alan Moore

Ranh giới từ là một vị trí có trước một ký tự từ và không được theo sau bởi một hoặc theo sau bởi một ký tự từ và không đi trước một ký tự.

Giả sử tôi có một chuỗi "Đây là một c a t, và cô ấy là một wgie", và tôi phải thay thế tất cả các lần xuất hiện của chữ 'a' chỉ khi chữ này tồn tại ở "Ranh giới của một từ" , nghĩa là akhông nên thay thế chữ bên trong 'mèo'.

Vì vậy, tôi sẽ thực hiện regex (bằng Python ) là

re.sub("\ba","e", myString.strip())// thay thế abằnge

do đó sản lượng sẽ Đây là ec một t end cô của ewesome


5

Tôi chạy vào một vấn đề còn tồi tệ hơn khi tìm kiếm văn bản cho chữ thích .NET, C++, C#, và C. Bạn sẽ nghĩ rằng các lập trình viên máy tính sẽ biết nhiều hơn là đặt tên cho một ngôn ngữ khó viết các cụm từ thông dụng.

Dù sao, đây là những gì tôi phát hiện ra (được tóm tắt chủ yếu từ http://www.THER-expressions.info , một trang web tuyệt vời): Trong hầu hết các hương vị của regex, các ký tự được khớp với lớp nhân vật tay ngắn \wlà các ký tự được coi là ký tự từ theo ranh giới từ. Java là một ngoại lệ. Java hỗ trợ Unicode cho \bnhưng không cho \w. (Tôi chắc chắn rằng có một lý do tốt cho nó tại thời điểm đó).

Chữ \wviết tắt của "từ nhân vật". Nó luôn khớp với các ký tự ASCII [A-Za-z0-9_]. Lưu ý sự bao gồm của dấu gạch dưới và chữ số (nhưng không phải dấu gạch ngang!). Trong hầu hết các hương vị hỗ trợ Unicode, \wbao gồm nhiều ký tự từ các tập lệnh khác. Có rất nhiều sự không nhất quán về các nhân vật thực sự được bao gồm. Các chữ cái và chữ số từ các chữ viết và chữ tượng hình thường được bao gồm. Dấu chấm câu kết nối khác với dấu gạch dưới và ký hiệu số không phải là chữ số có thể hoặc không bao gồm. Lược đồ XML và XPath thậm chí bao gồm tất cả các biểu tượng trong \w. Nhưng Java, JavaScript và PCRE chỉ khớp với các ký tự ASCII \w.

Đó là lý do dựa trên nền Java tìm kiếm regex cho C++, C#hoặc .NET(ngay cả khi bạn nhớ để thoát khỏi giai đoạn và pluses) được bắt vít vào \b.

Lưu ý: Tôi không biết phải làm gì về các lỗi trong văn bản, như khi ai đó không đặt dấu cách sau một khoảng thời gian ở cuối câu. Tôi đã cho phép, nhưng tôi không chắc chắn rằng đó là điều đúng đắn phải làm.

Dù sao, trong Java, nếu bạn đang tìm kiếm văn bản cho các ngôn ngữ có tên kỳ lạ đó, bạn cần thay thế \bbằng trước và sau các chỉ định khoảng trắng và dấu chấm câu. Ví dụ:

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

Sau đó, trong bài kiểm tra hoặc chức năng chính của bạn:

    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 Tôi cảm ơn http://regapidal.com/ mà không có ai, thế giới regex sẽ rất đau khổ!


Tôi cố gắng để hiểu lý do tại sao tôi không thể phù hợp C#nhưng bây giờ thì rõ ràng hơn
Mugoma J. Okomba 6/12/2016

4

Kiểm tra các tài liệu về các điều kiện biên:

http://java.sun.com/docs/books/tutorial/essential/regex/bound.html

Kiểm tra mẫu này:

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

Khi bạn in nó ra, lưu ý rằng đầu ra là thế này:

[Tôi tìm thấy giá trị -, trong chuỗi của tôi.]

Điều này có nghĩa là ký tự "-" không được chọn là nằm trên ranh giới của từ vì nó không được coi là ký tự từ. Có vẻ như @brianary kinda đánh tôi với cú đấm, vì vậy anh ta được bình chọn.


2

Ranh giới từ \ b được sử dụng trong đó một từ phải là ký tự từ và một từ khác là ký tự không phải từ. Biểu thức chính quy cho số âm phải là

--?\b\d+\b

kiểm tra DEMO làm việc


1

Tôi tin rằng vấn đề của bạn là do thực tế đó -không phải là một ký tự từ. Do đó, ranh giới từ sẽ khớp sau -, và do đó sẽ không nắm bắt được nó. Các ranh giới từ khớp với trước các ký tự từ đầu tiên và sau các ký tự từ cuối cùng trong một chuỗi, cũng như bất kỳ vị trí nào trước đó là một ký tự từ hoặc ký tự không từ và sau đó là ký tự ngược lại. Cũng lưu ý rằng ranh giới từ là một kết quả có độ rộng bằng không.

Một thay thế có thể là

(?:(?:^|\s)-?)\d+\b

Điều này sẽ khớp với bất kỳ số nào bắt đầu bằng ký tự khoảng trắng và dấu gạch ngang tùy chọn và kết thúc tại một ranh giới từ. Nó cũng sẽ khớp với một số bắt đầu từ đầu chuỗi.


0

Tôi nghĩ đó là ranh giới (tức là ký tự theo sau) của trận đấu cuối cùng hoặc bắt đầu hoặc kết thúc chuỗi.


1
Bạn đang nghĩ đến \G: khớp với phần đầu của chuỗi (như \A) trong lần thử khớp đầu tiên; sau đó nó phù hợp với vị trí mà trận đấu trước kết thúc.
Alan Moore

0

khi bạn sử dụng \\b(\\w+)+\\bđiều đó có nghĩa là khớp chính xác với một từ chỉ chứa các ký tự từ([a-zA-Z0-9])

trong trường hợp của bạn, ví dụ như cài đặt \\blúc bắt đầu regex sẽ chấp nhận -12(có khoảng trắng) nhưng một lần nữa nó sẽ không chấp nhận -12(không có khoảng trắng)

để tham khảo để hỗ trợ lời nói của tôi: https://docs.oracle.com/javase/tutorial/essential/regex/bound.html

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.