Biểu thức chính quy cho các từ trùng lặp


114

Tôi là một người mới sử dụng biểu thức chính quy và tôi không thể tìm ra cách viết một biểu thức chính quy duy nhất sẽ "khớp" với bất kỳ từ liên tiếp trùng lặp nào chẳng hạn như:

Paris trong các các lò xo.

Không phải điều đó có liên quan.

Tại sao bạn lại cười? Các biểu thức chính quy của tôi CÓ Xấu không ??

Có một biểu thức chính quy duy nhất sẽ khớp với TẤT CẢ các chuỗi in đậm ở trên không?


4
@poly: Đó không phải là "buộc tội", mà là một câu hỏi bình tĩnh, bình thường hoàn toàn có thể lấy "không" làm câu trả lời. @Joshua: Có, một số người (không quá ít) để trang web này làm bài tập về nhà cho họ. Nhưng đặt câu hỏi về nhà không phải là điều xấu để làm trên SO, khi chúng được gắn thẻ như vậy. Thông thường, phong cách của các câu trả lời thay đổi từ "đây là giải pháp" thành "đây là một số điều bạn chưa nghĩ đến", và đó là một điều tốt. Ai đó phải cố gắng và duy trì sự khác biệt, trong trường hợp của anh ấy là tôi, và ở những nơi khác "người khác" cũng làm điều tương tự. Đó là tất cả.
Tomalak

13
Hy vọng sẽ không bao giờ gặp một câu hỏi như "Điều này nghe có vẻ hơi giống một câu hỏi tại nơi làm việc. Phải không?" và sau đó mọi người sẽ tranh luận nếu tràn ngăn xếp đang thực hiện công việc của ai đó.
marcio

@Joshua +1 đối với giải pháp regex mà bạn đã chấp nhận, bạn có thể vui lòng cho tôi biết làm cách nào để thay thế các kết quả phù hợp (trùng lặp) bằng một phần tử của cặp (ví dụ: not that that is related-> not that is related) không? Cảm ơn trước
Antoine

@Joshua Tôi nghĩ rằng tôi đã tìm thấy giải pháp: Tôi nên thay thế bằng \1!
Antoine

2
@DavidLeal Làm thế nào về \b(\w+)\s+(\1\s*)+\b?
ytu

Câu trả lời:


141

Hãy thử biểu thức chính quy này:

\b(\w+)\s+\1\b

Đây \blà một ranh giới từ và \1tham chiếu đến trận đấu đã bắt của nhóm đầu tiên.


1
Làm tôi tự hỏi; là nó có thể làm \0quá? ( \0Toàn bộ regex ở đâu, tính đến thời điểm hiện tại HOẶC nơi \0đề cập đến toàn bộ regex)
Pindatjuh

@Pindatjuh: Không, tôi không nghĩ vậy vì trận đấu phụ đó cũng sẽ là một phần của cả trận đấu.
Gumbo

Ít nhất hoạt động trên công cụ regex được sử dụng trong hộp thoại tìm kiếm / thay thế Eclipse.
Chaos_99

3
Chỉ là một cảnh báo, điều này không xử lý các từ có dấu huyền hoặc (như Noel đã đề cập). Giải pháp của Mike hoạt động tốt hơn trong những trường hợp này

3
Hơn nữa, nó sẽ không bắt các bộ ba (hoặc nhiều hơn), không phải khi một trong các bộ trùng lặp / bộ ba ở cuối chuỗi
Nico

20

Tôi tin rằng regex này xử lý nhiều tình huống hơn:

/(\b\S+\b)\s+\b\1\b/

Bạn có thể tìm thấy lựa chọn tốt các chuỗi kiểm tra tại đây: http://callumacrae.github.com/regex-tuesday/challenge1.html


Tuyệt vời, hoạt động với dấu nháy đơn / dấu gạch nối / vv. quá - cảm ơn!

đối với liên kết challenge1, bạn đặt gì trong vùng thay thế để sử dụng từ được nhóm? Đã thử <strong>\0</strong>nhưng không hiệu quả.
uptownhr

2
Nó sẽ không bắt các bộ ba (hoặc nhiều hơn), không phải khi một trong các bộ trùng lặp / bộ ba ở cuối chuỗi
Nico

@uptownhr Bạn muốn sử dụng $1 <strong>$2</strong>. Nhưng cũng sử dụng regex khác nhau /\b(\S+) (\1)\b/gi. Đây là một liên kết: callumacrae.github.io/regex-tuesday/…
dsalaj

và Nếu tôi muốn tìm tất cả các từ liên tiếp từ một thẻ cụ thể, chẳng hạn như <p class="bebe">bla bla</p>làm cách nào để tích hợp công thức regex này?
Just Me

7

Hãy thử điều này với RE bên dưới

  • \ b bắt đầu từ ranh giới từ
  • \ W + bất kỳ ký tự từ nào
  • \ 1 từ giống nhau đã được khớp
  • \ b cuối từ
  • () * Lặp lại một lần nữa

    public static void main(String[] args) {
    
        String regex = "\\b(\\w+)(\\b\\W+\\b\\1\\b)*";//  "/* Write a RegEx matching repeated words here. */";
        Pattern p = Pattern.compile(regex, Pattern.CASE_INSENSITIVE/* Insert the correct Pattern flag here.*/);
    
        Scanner in = new Scanner(System.in);
    
        int numSentences = Integer.parseInt(in.nextLine());
    
        while (numSentences-- > 0) {
            String input = in.nextLine();
    
            Matcher m = p.matcher(input);
    
            // Check for subsequences of input that match the compiled pattern
            while (m.find()) {
                input = input.replaceAll(m.group(0),m.group(1));
            }
    
            // Prints the modified sentence.
            System.out.println(input);
        }
    
        in.close();
    }

5

Thư viện PCRE được sử dụng rộng rãi có thể xử lý các tình huống như vậy ( tuy nhiên, bạn sẽ không đạt được điều tương tự với các công cụ regex tuân thủ POSIX):

(\b\w+\b)\W+\1

Bạn cần một cái gì đó để khớp các ký tự giữa hai từ, như \W+. \bsẽ không làm điều đó, vì nó không sử dụng bất kỳ ký tự nào.
Alan Moore

Điều này có thể dẫn đến kết hợp dương tính giả trong các trường hợp như ... the these problems.... Giải pháp này không đáng tin cậy bằng cấu trúc chung của khuôn mẫu Gumbo, nó thực hiện đầy đủ các ranh giới từ.
mickmackusa

và Nếu tôi muốn tìm tất cả các từ liên tiếp từ một thẻ cụ thể, chẳng hạn như <p class="bebe">bla bla</p>làm cách nào để tích hợp công thức regex này?
Just Me

4

Đây là regex tôi sử dụng để xóa các cụm từ trùng lặp trong bot twitch của mình:

(\S+\s*)\1{2,}

(\S+\s*) tìm kiếm bất kỳ chuỗi ký tự nào không phải là khoảng trắng, theo sau là khoảng trắng.

\1{2,}sau đó tìm kiếm nhiều hơn 2 trường hợp của cụm từ đó trong chuỗi để đối sánh. Nếu có 3 cụm từ giống nhau thì nó trùng khớp.


Câu trả lời này gây hiểu lầm. Nó không săn các bản sao, nó săn các chuỗi con có 3 lần xuất hiện trở lên. Nó cũng không phải là rất mạnh mẽ vì \s*trong nhóm bắt giữ. Xem phần trình diễn này: regex101.com/r/JtCdd6/1
mickmackusa

Hơn nữa, các trường hợp cực đoan (văn bản tần số thấp) sẽ tạo ra các kết quả phù hợp dương tính giả. Ví dụ: I said "oioioi" that's some wicked mistressship!bật oioioisss
mickmackusa

4

Biểu thức dưới đây sẽ hoạt động chính xác để tìm bất kỳ số từ liên tiếp nào. So khớp có thể không phân biệt chữ hoa chữ thường.

String regex = "\\b(\\w+)(\\s+\\1\\b)*";
Pattern p = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);

Matcher m = p.matcher(input);

// Check for subsequences of input that match the compiled pattern
while (m.find()) {
     input = input.replaceAll(m.group(0), m.group(1));
}

Đầu vào mẫu: Tạm biệt tạm biệt GooDbYe

Đầu ra mẫu: Tạm biệt

Giải trình:

Biểu thức regex:

\ b: Bắt đầu một ranh giới từ

\ w +: Bất kỳ số ký tự từ nào

(\ s + \ 1 \ b) *: Bất kỳ số khoảng trắng nào theo sau của từ khớp với từ trước đó và kết thúc ranh giới từ. Toàn bộ nội dung được bao bọc trong * giúp tìm nhiều hơn một lần lặp lại.

Phân nhóm:

m.group (0): Sẽ chứa nhóm phù hợp trong trường hợp trên Tạm biệt tạm biệt GooDbYe

m.group (1): Sẽ chứa từ đầu tiên của mẫu phù hợp trong trường hợp trên Tạm biệt

Phương thức Replace sẽ thay thế tất cả các từ phù hợp liên tiếp bằng phiên bản đầu tiên của từ đó.


3

Không. Đó là một ngữ pháp bất quy tắc. Có thể có các biểu thức chính quy dành cho động cơ / ngôn ngữ cụ thể mà bạn có thể sử dụng, nhưng không có biểu thức chính quy phổ biến nào có thể làm điều đó.


12
Mặc dù đúng theo nghĩa chặt chẽ, tôi tin rằng không có công cụ regex nào được sử dụng nghiêm túc nữa mà không hỗ trợ nhóm và tham chiếu ngược.
Tomalak

3

Đây là một trong những bắt nhiều từ nhiều lần:

(\b\w+\b)(\s+\1)+

và Nếu tôi muốn tìm tất cả các từ liên tiếp từ một thẻ cụ thể, chẳng hạn như <p class="bebe">bla bla</p>làm cách nào để tích hợp công thức regex này?
Just Me

Tôi tin rằng điều đó sẽ yêu cầu phân tích cú pháp HTML. Đối với bất kỳ thẻ nhất định nào mà bạn muốn tìm kiếm, hãy tìm tất cả các lần xuất hiện thẻ bên trong HTML và chạy lần lượt regex này trên mỗi thẻ. Hoặc nếu bạn không chăm sóc về nơi trong HTML nào lặp lại xảy ra, nối tất cả các thuộc tính văn bản thẻ và chạy regex trên chuỗi nối
synaptikon

Tôi tự tìm cho mình câu trả lời<p class="bebe">.*?\b\s+(\w+)\b\K\s+\1\s+\b(?=.*?<\/p>)
Just Me

3

Regex to Strip 2+ từ trùng lặp (các từ liên tiếp / không liên tiếp)

Hãy thử regex này có thể bắt 2 từ trùng lặp trở lên và chỉ để lại một từ duy nhất. Và các từ trùng lặp thậm chí không cần phải liên tiếp .

/\b(\w+)\b(?=.*?\b\1\b)/ig

Ở đây, \bđược sử dụng cho Word Boundary, ?=được sử dụng cho lookahead tích cực và \1được sử dụng để tham chiếu ngược.

Nguồn ví dụ


1
Không liên tiếp là một ý tưởng tồi: "the cat sat on the mat"->" cat sat on the mat"
Walf

@Walf Đúng. Tuy nhiên, có những tình huống mà điều này được dự định. (ví dụ: trong khi
quét

Tại sao bạn lại phá vỡ regex của mình sau khi tôi sửa nó ? Bạn có nghĩ rằng tôi đã thay đổi ý định của nó? Ngay cả ví dụ bạn đã liên kết cũng không có lỗi.
Walf

Đúng, đó là một sai lầm, sao chép đã dán nội dung sai. Dự định sao chép một cái từ ví dụ của tôi thực sự. dù sao, nó bây giờ hoạt động! Vì vậy, tất cả tốt! Cảm ơn!
Niket Pathak

2

Ví dụ trong Javascript: Các phần tốt có thể được điều chỉnh để làm điều này:

var doubled_words = /([A-Za-z\u00C0-\u1FFF\u2800-\uFFFD]+)\s+\1(?:\s|$)/gi;

\ b sử dụng \ w cho các ranh giới từ, trong đó \ w tương đương với [0-9A-Z_a-z]. Nếu bạn không bận tâm về giới hạn đó, câu trả lời được chấp nhận là tốt.


2

Vì một số nhà phát triển đang truy cập trang này để tìm kiếm một giải pháp không chỉ loại bỏ các chuỗi con không có khoảng trắng liên tiếp trùng lặp, mà còn các chuỗi ba và hơn thế nữa, nên tôi sẽ hiển thị mẫu phù hợp.

Mẫu: /(\b\S+)(?:\s+\1\b)+/( Bản trình diễn mẫu )
Thay thế: $1(thay thế khớp chuỗi đầy đủ bằng nhóm chụp số 1)

Mẫu này đối sánh tham lam một chuỗi con "toàn bộ" không có khoảng trắng, sau đó yêu cầu một hoặc nhiều bản sao của chuỗi con phù hợp có thể được phân tách bằng một hoặc nhiều ký tự khoảng trắng (dấu cách, tab, dòng mới, v.v.).

Đặc biệt:

  • \b (ranh giới từ) các ký tự rất quan trọng để đảm bảo các từ từng phần không bị khớp.
  • Dấu ngoặc đơn thứ hai là nhóm không bắt giữ, bởi vì chuỗi con có độ rộng thay đổi này không cần được bắt - chỉ được khớp / hấp thụ.
  • các +(một hoặc nhiều lượng hóa) trên nhóm không chụp là thích hợp hơn **sẽ "làm phiền" động cơ regex để chụp và thay thế singleton lần xuất hiện - đây là lãng phí thiết kế mẫu.

* lưu ý nếu bạn đang xử lý các câu hoặc chuỗi đầu vào có dấu chấm câu, thì mẫu sẽ cần được hoàn thiện thêm.


@AdamJones sử dụng mẫu này trong dự án php của bạn. Câu trả lời của Nico có một số cú pháp không cần thiết trong đó.
mickmackusa

1

Biểu thức này (lấy cảm hứng từ Mike, ở trên) dường như nắm bắt tất cả các bản sao, bộ ba, v.v., bao gồm cả những cái ở cuối chuỗi, mà hầu hết những cái khác không:

/(^|\s+)(\S+)(($|\s+)\2)+/g, "$1$2")

Tôi biết câu hỏi được yêu cầu chỉ để đối sánh các bản sao , nhưng một bản ba chỉ là 2 bản sao bên cạnh nhau :)

Đầu tiên, tôi (^|\s+)phải đảm bảo rằng nó bắt đầu bằng một từ đầy đủ, nếu không "món bít tết của trẻ" sẽ chuyển thành "món bít tết con" (chữ "s" sẽ khớp với nhau). Sau đó, nó khớp với tất cả các từ đầy đủ ( (\b\S+\b)), theo sau là một phần cuối của chuỗi ( $) hoặc một số khoảng trắng ( \s+), toàn bộ được lặp lại nhiều lần.

Tôi đã thử nó như thế này và nó hoạt động tốt:

var s = "here here here     here is ahi-ahi ahi-ahi ahi-ahi joe's joe's joe's joe's joe's the result result     result";
print( s.replace( /(\b\S+\b)(($|\s+)\1)+/g, "$1"))         
--> here is ahi-ahi joe's the result

Tôi đang gặp sự cố khi viết lại điều này vào PHP, điều quan trọng là tôi nhận được một bản sao duy nhất của bản sao phù hợp để thay thế mỗi lần xuất hiện các bản sao / bản sao ba lần, v.v. Cho đến nay, tôi có: preg_replace ('/ (^ | \ s +) (\ S +) ( ($ | \ s +) \ 2) + / im ',' $ 0 ', $ string);
AdamJones

Đây là câu trả lời tốt nhất. Tôi vừa thực hiện một chỉnh sửa cho điều đó bằng cách thêm \bvào cuối như sau: /(^|\s+)(\S+)(($|\s+)\2)+\b/g, "$1$2")Điều này sau đó sẽ hoạt động cho các tình huống như thế này: the the string String string stringing the the along the the stringsẽ trở thành the string stringing the along the stringThông báo string stringing. Nó phù hợp với câu trả lời của bạn. Cảm ơn bạn.
Ste

-1

Sử dụng điều này trong trường hợp bạn muốn kiểm tra phân biệt chữ hoa chữ thường để tìm các từ trùng lặp.

(?i)\\b(\\w+)\\s+\\1\\b

Việc sử dụng công cụ sửa đổi mẫu không phân biệt chữ hoa chữ thường sẽ không có ích cho mẫu của bạn. Không có phạm vi chữ cái nào để cờ tác động.
mickmackusa

Đây thực sự là một bản sao của câu trả lời được chấp nhận và không có giá trị gì cho trang. Vui lòng xem xét loại bỏ câu trả lời này để giảm tình trạng phồng trang.
mickmackusa
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.