นิพจน์ทั่วไปสำหรับคำที่ซ้ำกัน


114

ฉันเป็นมือใหม่ในการใช้นิพจน์ทั่วไปและฉันไม่สามารถเข้าใจได้ว่าจะเขียนนิพจน์ทั่วไปเพียงคำเดียวที่จะ "จับคู่" คำใด ๆ ที่ซ้ำกันติดต่อกันเช่น:

ปารีสในที่ฤดูใบไม้ผลิ

ไม่ว่าจะเกี่ยวข้องกัน

คุณหัวเราะทำไม? เป็นของฉันแสดงออกปกติที่ไม่ดี ??

มีนิพจน์ทั่วไปเดียวที่จะตรงกับสตริงตัวหนาด้านบนทั้งหมดหรือไม่


4
@poly: นั่นไม่ใช่ "ข้อกล่าวหา" แต่เป็นคำถามที่สงบและธรรมดาที่สามารถใช้ "ไม่" เป็นคำตอบได้ @ โจชัว: ใช่บางคน (ไม่น้อยเกินไป) ปล่อยให้เว็บไซต์นี้ทำการบ้านให้พวกเขา แต่การถามคำถามการบ้านไม่ใช่เรื่องแย่ที่จะทำใน SO เมื่อมีการแท็กเช่น โดยปกติรูปแบบของคำตอบจะเปลี่ยนจาก "ที่นี่คือทางแก้" เป็น "นี่คือบางสิ่งที่คุณไม่ได้คิด" และนั่นก็เป็นสิ่งที่ดี ใครบางคนต้องพยายามรักษาความแตกต่างในกรณีของเขาก็คือฉันและที่อื่น "คนอื่น" ก็ทำเช่นเดียวกัน นั่นคือทั้งหมด
Tomalak

13
หวังว่าจะไม่เคยเห็นคำถามเช่น "คำถามนี้ฟังดูเหมือนคำถามในที่ทำงานใช่ไหม" จากนั้นผู้คนก็จะโต้แย้งว่าถ้าสแต็กล้นกำลังทำงานของใครบางคน
marcio

@Joshua +1 เกี่ยวกับโซลูชัน regex ที่คุณยอมรับคุณช่วยบอกฉันได้ไหมว่าฉันจะแทนที่การจับคู่ (รายการที่ซ้ำกัน) ด้วยองค์ประกอบหนึ่งของคู่ (เช่นnot that that is related-> not that is related) ได้อย่างไร ขอบคุณล่วงหน้า
Antoine

@ โจชัวฉันคิดว่าฉันพบทางออกแล้ว: ฉันควรเปลี่ยนด้วย\1!
Antoine

2
@DavidLeal แล้วไง\b(\w+)\s+(\1\s*)+\b?
ytu

คำตอบ:


141

ลองใช้นิพจน์ทั่วไปนี้:

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

นี่\bคือขอบเขตคำและ\1อ้างอิงการจับคู่ที่จับได้ของกลุ่มแรก


1
ทำให้ฉันสงสัย; เป็นไปได้\0ไหม ( \0regex ทั้งหมดอยู่ที่ไหนจนถึงจุดปัจจุบันหรือที่\0หมายถึง regex ทั้งหมด)
Pindatjuh

@Pindatjuh: ไม่ฉันไม่คิดอย่างนั้นเพราะการแข่งขันย่อยนั้นจะเป็นส่วนหนึ่งของการแข่งขันทั้งหมดด้วย
Gumbo

อย่างน้อยก็ใช้ได้กับเอนจิน regex ที่ใช้ในไดอะล็อกค้นหา / แทนที่ Eclipse
Chaos_99

3
คำเตือนนี้ไม่ได้ใช้กับคำที่มีเครื่องหมายอะพอสทรอฟีหรือ (ตามที่โนเอลกล่าวถึง) วิธีแก้ปัญหาของ Mike ทำงานได้ดีขึ้นในกรณีเหล่านี้

3
ยิ่งไปกว่านั้นมันจะไม่จับ triplicates (หรือมากกว่า) ไม่ใช่เมื่อหนึ่งใน dup / triplicate อยู่ท้ายสตริง
Nico

20

ฉันเชื่อว่า regex นี้สามารถจัดการสถานการณ์ต่างๆได้มากขึ้น:

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

คุณสามารถดูสตริงการทดสอบที่คัดสรรมาอย่างดีได้ที่นี่: http://callumacrae.github.com/regex-t Tuesday/challenge1.html


เยี่ยมมากใช้ได้กับเครื่องหมายวรรคตอน / ยัติภังค์ / ฯลฯ ด้วย - ขอบคุณ!

สำหรับลิงก์ challenge1 คุณวางอะไรในพื้นที่แทนที่เพื่อใช้คำที่จัดกลุ่ม พยายาม<strong>\0</strong>แต่ไม่ได้ผล
uptownhr

2
มันจะไม่จับ triplicates (หรือมากกว่า) ไม่ใช่เมื่อหนึ่งใน dup / triplicate อยู่ท้ายสตริง
Nico

@uptownhr คุณต้องการใช้$1 <strong>$2</strong>. แต่ยังใช้ /\b(\S+) (\1)\b/giregex นี่คือลิงค์: callumacrae.github.io/regex-t Tuesday/…
dsalaj

และหากฉันต้องการค้นหาคำที่ต่อเนื่องกันทั้งหมดจากแท็กใดแท็กหนึ่งเช่น<p class="bebe">bla bla</p>ฉันจะรวมสูตร regex นี้ได้อย่างไร
Just Me

7

ลองใช้กับด้านล่าง RE

  • \ b จุดเริ่มต้นของขอบเขตคำ
  • \ W + อักขระคำใด ๆ
  • \ 1 คำเดียวกันที่ตรงกันแล้ว
  • \ b ท้ายคำ
  • () * ทำซ้ำอีกครั้ง

    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

ห้องสมุด PCRE ใช้กันอย่างแพร่หลายสามารถจัดการกับสถานการณ์ดังกล่าว (คุณจะไม่ประสบความสำเร็จที่เดียวกันกับเครื่องยนต์ regex POSIX สอดคล้องแม้ว่า):

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

คุณจำเป็นต้องมีบางสิ่งบางอย่างเพื่อให้ตรงกับตัวละครระหว่าง\W+คำสองคำเช่น \bจะไม่ทำเพราะมันไม่กินอักขระใด ๆ
Alan Moore

... the these problems...นี้อาจจะมีผลในการจับคู่บวกเท็จในกรณีเช่น โซลูชันนี้ไม่น่าเชื่อถือเท่ากับโครงสร้างทั่วไปของรูปแบบของ Gumbo ซึ่งใช้ขอบเขตของคำอย่างเพียงพอ
mickmackusa

และหากฉันต้องการค้นหาคำที่ต่อเนื่องกันทั้งหมดจากแท็กใดแท็กหนึ่งเช่น<p class="bebe">bla bla</p>ฉันจะรวมสูตร regex นี้ได้อย่างไร
Just Me

5

นิพจน์ด้านล่างควรทำงานได้อย่างถูกต้องเพื่อค้นหาจำนวนคำที่ต่อเนื่องกัน การจับคู่อาจไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่

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

อินพุตตัวอย่าง: Goodbyebye Goodbye GooDbYe

ตัวอย่างผลลัพธ์: ลาก่อน

คำอธิบาย:

นิพจน์ regex:

\ b: จุดเริ่มต้นของขอบเขตคำ

\ w +: อักขระคำจำนวนเท่าใดก็ได้

(\ s + \ 1 \ b) *: ช่องว่างจำนวนเท่าใดก็ได้ตามด้วยคำที่ตรงกับคำก่อนหน้าและสิ้นสุดขอบเขตของคำ สิ่งที่ห่อด้วย * ช่วยในการค้นหาการทำซ้ำมากกว่าหนึ่งครั้ง

การจัดกลุ่ม:

m.group (0): จะมีกลุ่มที่ตรงกันในกรณีด้านบน Goodbyebyebye GooDbYe

m.group (1): จะมีคำแรกของรูปแบบที่ตรงกันในกรณีข้างต้น Goodbye

วิธีการแทนที่จะแทนที่คำที่จับคู่ติดต่อกันทั้งหมดด้วยตัวอย่างแรกของคำ


4

นี่คือ regex ที่ฉันใช้เพื่อลบวลีที่ซ้ำกันในบอท Twitch ของฉัน:

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

(\S+\s*) ค้นหาสตริงของอักขระที่ไม่ใช่ช่องว่างแล้วตามด้วยช่องว่าง

\1{2,}จากนั้นค้นหามากกว่า 2 อินสแตนซ์ของวลีนั้นในสตริงที่จะจับคู่ หากมี 3 วลีที่เหมือนกันแสดงว่าตรงกัน


คำตอบนี้ทำให้เข้าใจผิด ไม่ล่าสัตว์ที่ซ้ำกันมันล่าสตริงย่อยที่มี 3 เหตุการณ์ขึ้นไป นอกจากนี้ยังไม่แข็งแกร่งมากเนื่องจาก\s*อยู่ในกลุ่มการจับภาพ ดูการสาธิตนี้: regex101.com/r/JtCdd6/1
mickmackusa

นอกจากนี้กรณีที่รุนแรง (ข้อความความถี่ต่ำ) จะทำให้เกิดการจับคู่ที่ผิดพลาด เช่นI said "oioioi" that's some wicked mistressship!on oioioiandsss
mickmackusa

3

ไม่นั่นเป็นไวยากรณ์ที่ผิดปกติ อาจมีนิพจน์ทั่วไปเฉพาะของเครื่องยนต์ / ภาษาที่คุณสามารถใช้ได้ แต่ไม่มีนิพจน์ทั่วไปทั่วไปที่สามารถทำได้


12
แม้ว่าจะถูกต้องในแง่ที่เข้มงวด แต่ฉันเชื่อว่าไม่มีเอนจิ้น regex ที่ใช้งานจริงจังอีกต่อไปที่ไม่รองรับการจัดกลุ่มและการอ้างอิงย้อนกลับ
Tomalak

3

นี่คือคำที่จับได้หลายคำหลายครั้ง:

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

และหากฉันต้องการค้นหาคำที่ต่อเนื่องกันทั้งหมดจากแท็กใดแท็กหนึ่งเช่น<p class="bebe">bla bla</p>ฉันจะรวมสูตร regex นี้ได้อย่างไร
Just Me

ฉันเชื่อว่าจะต้องมีการแยกวิเคราะห์ HTML สำหรับแท็กใด ๆ ที่คุณต้องการค้นหาให้ค้นหาแท็กทั้งหมดที่เกิดขึ้นภายใน HTML และเรียกใช้ regex นี้ทีละแท็กในแต่ละแท็ก หรือถ้าคุณไม่สนใจว่าการทำซ้ำจะเกิดขึ้นที่ใดใน HTML ให้ต่อแอตทริบิวต์ข้อความแท็กทั้งหมดเข้าด้วยกันและเรียกใช้ regex บนสตริงที่ต่อกัน
synaptikon

ฉันพบคำตอบด้วยตัวเอง<p class="bebe">.*?\b\s+(\w+)\b\K\s+\1\s+\b(?=.*?<\/p>)
Just Me

3

Regex ถึง Strip 2+ คำที่ซ้ำกัน (คำที่ต่อเนื่องกัน / ไม่ต่อเนื่องกัน)

ลองใช้นิพจน์ทั่วไปนี้ที่สามารถจับคำที่ซ้ำกันตั้งแต่ 2 คำขึ้นไปและทิ้งไว้เพียงคำเดียว และคำที่ซ้ำกันไม่จำเป็นต้องติดต่อกันด้วยซ้ำ

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

ที่นี่\bใช้สำหรับ Word Boundary ?=ใช้สำหรับการมองเชิงบวกและ\1ใช้สำหรับการอ้างอิงกลับ

แหล่งที่มาตัวอย่าง


1
การไม่ติดต่อกันเป็นความคิดที่ไม่ดี: "the cat sat on the mat"->" cat sat on the mat"
Walf

@ วอล์ฟทรู. อย่างไรก็ตามมีสถานการณ์ที่ตั้งใจไว้ (ตัวอย่าง: ขณะขูดข้อมูล)
Niket Pathak

ทำไมคุณทำลาย regex ของคุณอีกครั้งหลังจากที่ผมแก้ไขมัน ? คุณคิดว่าฉันเปลี่ยนเจตนาหรือไม่? แม้แต่ตัวอย่างที่คุณเชื่อมโยงก็ไม่มีข้อผิดพลาด
Walf

ใช่มันเป็นความผิดพลาดคัดลอกวางสิ่งที่ไม่ถูกต้อง ตั้งใจจะคัดลอกจากตัวอย่างของฉันจริง ตอนนี้ใช้งานได้แล้ว! ดีมาก! ขอบคุณ!
Niket Pathak

2

ตัวอย่างใน Javascript: Good Parts สามารถปรับให้ทำสิ่งนี้ได้:

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

\ b ใช้ \ w สำหรับขอบเขตของคำโดยที่ \ w เทียบเท่ากับ [0-9A-Z_a-z] หากคุณไม่คำนึงถึงข้อ จำกัด ดังกล่าวคำตอบที่ยอมรับก็ใช้ได้


2

เนื่องจากนักพัฒนาบางรายเข้ามาที่หน้านี้เพื่อค้นหาโซลูชันซึ่งไม่เพียง แต่กำจัดสตริงย่อยที่ไม่ใช่ช่องว่างที่ซ้ำกันที่ซ้ำกัน แต่ยังรวมถึงสามมิติและอื่น ๆ ฉันจะแสดงรูปแบบที่ปรับแล้ว

รูปแบบ: /(\b\S+)(?:\s+\1\b)+/(การสาธิตรูปแบบ )
แทนที่: $1(แทนที่การจับคู่แบบเต็มสตริงด้วยกลุ่มการจับภาพ # 1)

รูปแบบนี้จับคู่กับสตริงย่อยที่ไม่ใช่ช่องว่างแบบ "ทั้งหมด" จากนั้นต้องการสำเนาของสตริงย่อยที่ตรงกันอย่างน้อยหนึ่งชุดซึ่งอาจคั่นด้วยอักขระช่องว่างอย่างน้อยหนึ่งตัว (ช่องว่างแท็บขึ้นบรรทัดใหม่ ฯลฯ )

โดยเฉพาะ:

  • \b (ขอบเขตคำ) อักขระมีความสำคัญเพื่อให้แน่ใจว่าคำบางส่วนไม่ตรงกัน
  • วงเล็บที่สองเป็นกลุ่มที่ไม่จับภาพเนื่องจากไม่จำเป็นต้องจับสตริงย่อยความกว้างตัวแปรนี้ - จับคู่ / ดูดซับเท่านั้น
  • +(หนึ่งหรือมากกว่าปริมาณ) ในกลุ่มที่ไม่ใช่การจับมีความเหมาะสมกว่า*เพราะ*จะ "ตื๊อ" เครื่องยนต์ regex เพื่อจับภาพและแทนที่เดี่ยวเกิดขึ้น - นี้คือการออกแบบรูปแบบสิ้นเปลือง

* สังเกตว่าคุณกำลังจัดการกับประโยคหรือสตริงอินพุตที่มีเครื่องหมายวรรคตอนรูปแบบจะต้องได้รับการปรับปรุงเพิ่มเติม


@AdamJones ใช้รูปแบบนี้ในโครงการ php ของคุณ คำตอบของ Nico มีไวยากรณ์ที่ไม่จำเป็นอยู่ในนั้น
mickmackusa

1

นิพจน์นี้ (ได้รับแรงบันดาลใจจาก Mike ด้านบน) ดูเหมือนว่าจะตรวจจับรายการที่ซ้ำกัน triplicates และอื่น ๆ ทั้งหมดรวมถึงประโยคที่อยู่ท้ายสตริงซึ่งส่วนใหญ่ไม่:

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

ฉันรู้ว่าคำถามที่ถามให้จับคู่รายการที่ซ้ำกันเท่านั้น แต่สามรายการเป็นเพียง 2 รายการที่ซ้ำกัน :)

อันดับแรกฉัน(^|\s+)ต้องแน่ใจว่ามันขึ้นต้นด้วยคำเต็มมิฉะนั้น "สเต็กเด็ก" จะไปที่ "child'steak" ("s" จะตรงกัน) จากนั้นจะจับคู่คำเต็มทั้งหมด ( (\b\S+\b)) ตามด้วยจุดจบของสตริง ( $) หรือช่องว่างจำนวนหนึ่ง ( \s+) ทั้งคำซ้ำมากกว่าหนึ่งครั้ง

ฉันลองแบบนี้แล้วมันก็ใช้ได้ดี:

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

ฉันมีปัญหาในการเขียนสิ่งนี้ใหม่เป็น PHP มันสำคัญมากที่ฉันจะได้รับสำเนาที่ตรงกันเพียงชุดเดียวแทนที่รายการที่ซ้ำกัน / triplicates แต่ละครั้งจนถึงตอนนี้ฉันมี: preg_replace ('/ (^ | \ s +) (\ S +) ( ($ | \ s +) \ 2) + / im ',' $ 0 ', $ string);
AdamJones

นี่คือคำตอบที่ดีที่สุด ฉันเพียงแค่ทำบิดที่ได้โดยการเพิ่ม\bการ end เช่นดังนั้น: /(^|\s+)(\S+)(($|\s+)\2)+\b/g, "$1$2")นี้จะทำงานแล้วสำหรับสถานการณ์เช่นนี้the the string String string stringing the the along the the stringจะกลายเป็นเวปไซด์the string stringing the along the string string stringingตรงกับคำตอบของคุณ ขอบคุณ.
Ste

-1

ใช้สิ่งนี้ในกรณีที่คุณต้องการตรวจสอบคำที่ซ้ำกันโดยไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่

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

การใช้ตัวปรับเปลี่ยนรูปแบบที่ไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่จะไม่ใช้กับรูปแบบของคุณ ไม่มีช่วงตัวอักษรเพื่อให้แฟล็กกระทบ
mickmackusa

นี่เป็นการซ้ำกับคำตอบที่ยอมรับได้อย่างมีประสิทธิภาพและไม่เพิ่มคุณค่าให้กับเพจ โปรดพิจารณาลบคำตอบนี้เพื่อลดการบวมของหน้า
mickmackusa
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.