Ekspresi Reguler Untuk Kata Duplikat


114

Saya pemula ekspresi reguler, dan saya tidak tahu cara menulis ekspresi reguler tunggal yang akan "cocok" dengan kata duplikat yang berurutan seperti:

Paris di dalam yang semi.

Bukan itu yang terkait.

Mengapa kamu tertawa? Apakah ekspresi reguler saya ITU buruk ??

Apakah ada satu ekspresi reguler yang akan cocok dengan SEMUA string tebal di atas?


4
@poly: Itu bukanlah "tuduhan", tapi pertanyaan yang tenang dan normal yang secara sempurna dapat mengambil "tidak" sebagai jawaban. @ Joshua: Ya, beberapa orang (tidak terlalu sedikit) membiarkan situs ini mengerjakan pekerjaan rumahnya untuk mereka. Tetapi mengajukan pertanyaan pekerjaan rumah bukanlah hal yang buruk untuk dilakukan di SO, jika diberi tag seperti itu. Biasanya gaya jawaban berubah dari "inilah solusinya" menjadi "ini beberapa hal yang belum Anda pikirkan", dan itu hal yang baik. Seseorang harus mencoba dan mempertahankan perbedaannya, dalam kasusnya itu adalah saya, dan di tempat lain "orang lain" melakukan hal yang sama. Itu saja.
Tomalak

13
Berharap untuk tidak pernah melihat pertanyaan seperti "Ini terdengar seperti pertanyaan di tempat kerja. Benarkah?" dan kemudian orang akan berdebat jika stack overflow melakukan pekerjaan seseorang.
marcio

@Joshua +1 sehubungan dengan solusi regex yang Anda terima, dapatkah Anda memberi tahu saya bagaimana cara mengganti kecocokan (duplikat) dengan satu elemen pasangan (misalnya, not that that is related-> not that is related)? Terima kasih sebelumnya
Antoine

@ Joshua Saya rasa saya menemukan solusinya: Saya harus mengganti dengan \1!
Antoine

2
@DavidLeal Bagaimana dengan \b(\w+)\s+(\1\s*)+\b?
ytu

Jawaban:


141

Coba ekspresi reguler ini:

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

Berikut \badalah batas kata dan \1referensi kecocokan yang ditangkap dari grup pertama.


1
Membuat saya bertanya-tanya; apakah mungkin untuk dilakukan \0juga? (Di mana \0seluruh regex, hingga titik saat ini ATAU di mana \0mengacu pada seluruh regex)
Pindatjuh

@Pindatjuh: Tidak, saya rasa tidak karena sub-pertandingan itu juga akan menjadi bagian dari keseluruhan pertandingan.
Gumbo

Setidaknya berfungsi pada mesin regex yang digunakan dalam dialog pencarian / ganti Eclipse.
Chaos_99

3
Sekadar peringatan, ini tidak menangani kata-kata dengan apostrof atau (seperti yang disebutkan Noel) tanda hubung. Solusi Mike bekerja lebih baik dalam kasus ini

3
Selain itu, itu tidak akan menangkap rangkap tiga (atau lebih), tidak ketika salah satu dup / rangkap tiga berada di akhir string
Nico

20

Saya yakin regex ini menangani lebih banyak situasi:

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

Pilihan string pengujian yang baik dapat ditemukan di sini: http://callumacrae.github.com/regex-tuesday/challenge1.html


Bagus, berfungsi dengan apostrof / tanda hubung / dll. juga - terima kasih!

untuk tautan challenge1, apa yang Anda tempatkan di area ganti untuk menggunakan kata yang dikelompokkan? Sudah mencoba <strong>\0</strong>tapi tidak berhasil.
Uptownhr

2
Itu tidak akan menangkap rangkap tiga (atau lebih), tidak ketika salah satu dup / rangkap tiga ada di akhir string
Nico

@uptownhr Anda ingin menggunakan $1 <strong>$2</strong>. Tetapi juga menggunakan regex yang berbeda /\b(\S+) (\1)\b/gi. Ini tautannya: callumacrae.github.io/regex-tuesday/…
dsalaj

dan Jika saya ingin menemukan semua kata yang berurutan dari tag tertentu, seperti <p class="bebe">bla bla</p>bagaimana cara mengintegrasikan rumus regex ini?
Just Me

7

Coba ini dengan RE di bawah ini

  • \ b awal batas kata kata
  • \ W + karakter kata apapun
  • \ 1 kata yang sama sudah cocok
  • \ b akhir kata
  • () * Mengulangi lagi

    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

Pustaka PCRE yang banyak digunakan dapat menangani situasi seperti itu (Anda tidak akan mencapai hal yang sama dengan mesin regex yang sesuai dengan POSIX):

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

Anda membutuhkan sesuatu untuk mencocokkan karakter antara dua kata, seperti \W+. \btidak akan melakukannya, karena tidak mengonsumsi karakter apa pun.
Alan Moore

Ini berpotensi menghasilkan pencocokan positif palsu dalam kasus seperti ... the these problems.... Solusi ini tidak dapat diandalkan seperti struktur umum pola Gumbo yang cukup mengimplementasikan batasan kata.
mickmackusa

dan Jika saya ingin menemukan semua kata yang berurutan dari tag tertentu, seperti <p class="bebe">bla bla</p>bagaimana cara mengintegrasikan rumus regex ini?
Just Me

4

Ini adalah regex yang saya gunakan untuk menghapus frasa duplikat di bot kedutan saya:

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

(\S+\s*) mencari string karakter apa pun yang bukan spasi, diikuti spasi.

\1{2,}lalu mencari lebih dari 2 contoh frasa itu dalam string untuk dicocokkan. Jika ada 3 frasa yang identik, itu cocok.


Jawaban ini menyesatkan. Itu tidak berburu duplikat, itu berburu substring dengan 3 kejadian atau lebih. Itu juga tidak terlalu kuat karena \s*dalam kelompok penangkapan. Lihat demonstrasi ini: regex101.com/r/JtCdd6/1
mickmackusa

Selanjutnya kasus ekstrim (teks frekuensi rendah) akan menghasilkan kecocokan positif palsu. Misalnya I said "oioioi" that's some wicked mistressship!pada oioioidansss
mickmackusa

4

Ekspresi di bawah ini harus bekerja dengan benar untuk menemukan sejumlah kata yang berurutan. Pencocokan bisa peka huruf besar / kecil.

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

Contoh Masukan: Selamat tinggal selamat tinggal GooDbYe

Output Sampel: Selamat tinggal

Penjelasan:

Ekspresi regex:

\ b: Awal dari batas kata

\ w +: Sejumlah karakter kata

(\ s + \ 1 \ b) *: Sejumlah spasi diikuti kata yang cocok dengan kata sebelumnya dan mengakhiri batas kata. Seluruh hal yang dibungkus * membantu menemukan lebih dari satu pengulangan.

Pengelompokan:

m.group (0): Akan berisi grup yang cocok dalam kasus di atas. Selamat tinggal, selamat tinggal GooDbYe

m.group (1): Berisi kata pertama dari pola yang cocok dalam kasus di atas Selamat tinggal

Metode Replace akan mengganti semua kata yang cocok secara berurutan dengan contoh kata pertama.


3

Tidak. Itu adalah tata bahasa yang tidak teratur. Mungkin ada persamaan reguler khusus mesin / bahasa yang dapat Anda gunakan, tetapi tidak ada persamaan reguler universal yang dapat melakukannya.


12
Meskipun benar dalam arti yang sempit, saya yakin tidak ada mesin regex yang sedang digunakan secara serius yang tidak mendukung pengelompokan dan referensi balik.
Tomalak

3

Ini adalah salah satu yang menangkap banyak kata berkali-kali:

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

dan Jika saya ingin menemukan semua kata yang berurutan dari tag tertentu, seperti <p class="bebe">bla bla</p>bagaimana cara mengintegrasikan rumus regex ini?
Just Me

Saya yakin itu akan membutuhkan parsing HTML. Untuk setiap tag tertentu yang ingin Anda telusuri, temukan semua kemunculan tag di dalam HTML, dan jalankan regex ini satu per satu di setiap tag. Atau jika Anda tidak peduli di mana di HTML mana pengulangan terjadi, gabungkan semua atribut teks tag dan jalankan regex pada string gabungan
synaptikon

Saya menemukan diri saya jawabannya<p class="bebe">.*?\b\s+(\w+)\b\K\s+\1\s+\b(?=.*?<\/p>)
Just Me

3

Regex untuk Menghapus 2+ kata duplikat (kata berurutan / tidak berurutan)

Coba regex ini yang dapat menangkap 2 atau lebih kata duplikat dan hanya meninggalkan satu kata. Dan kata - kata duplikatnya bahkan tidak harus berurutan .

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

Di sini, \bdigunakan untuk Word Boundary, ?=digunakan untuk lookahead positif, dan \1digunakan untuk referensi balik.

Contoh Sumber


1
Tidak berurutan adalah ide yang buruk: "the cat sat on the mat"->" cat sat on the mat"
Walf

@Setengah Benar. Namun demikian, ada skenario di mana hal ini dimaksudkan. (Misalnya: saat
mengumpulkan

Kenapa kamu merusak ekspresi reguler Anda lagi setelah saya memperbaikinya ? Apakah Anda pikir saya telah mengubah niatnya? Bahkan contoh yang Anda tautkan tidak memiliki kesalahan.
Walf

Ya, itu adalah kesalahan, salin menempelkan barang yang salah. Dimaksudkan untuk menyalin salah satu dari contoh saya sebenarnya. bagaimanapun, sekarang ini berhasil! jadi semuanya baik-baik saja! Terima kasih!
Niket Pathak

2

Contoh di Javascript: The Good Parts dapat disesuaikan untuk melakukan ini:

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

\ b menggunakan \ w untuk batas kata, di mana \ w sama dengan [0-9A-Z_a-z]. Jika Anda tidak keberatan dengan batasan itu, jawaban yang diterima baik-baik saja.


2

Karena beberapa pengembang datang ke halaman ini untuk mencari solusi yang tidak hanya menghilangkan duplikat substring non-spasi kosong, tetapi tiga kali lipat dan seterusnya, saya akan menunjukkan pola yang disesuaikan.

Pola: /(\b\S+)(?:\s+\1\b)+/( Demo Pola )
Ganti: $1(menggantikan pertandingan fullstring dengan grup penangkapan # 1)

Pola ini secara serakah mencocokkan substring non spasi kosong "utuh", kemudian memerlukan satu atau lebih salinan substring yang cocok yang mungkin dibatasi oleh satu atau lebih karakter spasi putih (spasi, tab, baris baru, dll).

Secara khusus:

  • \b Karakter (batas kata) sangat penting untuk memastikan sebagian kata tidak cocok.
  • Tanda kurung kedua adalah grup non-capturing, karena substring lebar variabel ini tidak perlu ditangkap - hanya cocok / diserap.
  • the +(satu atau lebih pembilang) pada grup non-capturing lebih tepat daripada *karena *akan "mengganggu" mesin regex untuk menangkap dan mengganti kejadian tunggal - ini adalah desain pola yang boros.

* Catatan jika Anda berurusan dengan kalimat atau string input dengan tanda baca, maka polanya perlu disempurnakan lebih lanjut.


@AdamJones menggunakan pola ini dalam proyek php Anda. Jawaban Nico memiliki sintaks yang tidak perlu di dalamnya.
mickmackusa

1

Ekspresi ini (terinspirasi dari Mike, di atas) tampaknya menangkap semua duplikat, rangkap tiga, dll, termasuk yang ada di akhir string, yang sebagian besar tidak:

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

Saya tahu pertanyaan yang diminta untuk mencocokkan duplikat saja, tetapi rangkap tiga hanyalah 2 duplikat di samping satu sama lain :)

Pertama, saya (^|\s+)pastikan itu dimulai dengan kata lengkap, jika tidak "steak anak" akan menjadi "steak anak" ("s" akan cocok). Kemudian, itu cocok dengan semua kata lengkap ( (\b\S+\b)), diikuti dengan akhir string ( $) atau sejumlah spasi ( \s+), keseluruhannya diulang lebih dari sekali.

Saya mencobanya seperti ini dan berhasil dengan baik:

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

Saya mengalami kesulitan menulis ulang ini ke PHP, sangat penting saya mendapatkan satu salinan dari duplikat yang cocok menggantikan setiap kemunculan duplikat / rangkap tiga dll. Sejauh ini saya punya: preg_replace ('/ (^ | \ s +) (\ S +) ( ($ | \ s +) \ 2) + / im ',' $ 0 ', $ string);
AdamJones

Ini jawaban terbaik. Saya baru saja membuat tweak dengan menambahkan \bakhir seperti /(^|\s+)(\S+)(($|\s+)\2)+\b/g, "$1$2")ini : Ini kemudian akan bekerja untuk situasi seperti ini: the the string String string stringing the the along the the stringakan menjadi the string stringing the along the stringNotice string stringing. Itu cocok dengan jawaban Anda. Terima kasih.
Ste

-1

Gunakan ini jika Anda ingin pemeriksaan case-insensitive untuk kata-kata duplikat.

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

Menggunakan pengubah pola case-insensitive tidak berguna untuk pola Anda. Tidak ada rentang huruf agar bendera terpengaruh.
mickmackusa

Ini secara efektif merupakan duplikat dari jawaban yang diterima dan tidak menambah nilai ke halaman. Harap pertimbangkan untuk menghapus jawaban ini untuk mengurangi pembengkakan halaman.
mickmackusa
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.