Espressione regolare per parole duplicate


114

Sono un principiante delle espressioni regolari e non riesco a capire come scrivere una singola espressione regolare che "corrisponda" a qualsiasi parola consecutiva duplicata come:

Parigi la la primavera.

Non che sia correlato.

Perché stai ridendo? Le mie espressioni regolari sono così cattive?

Esiste una singola espressione regolare che corrisponderà a TUTTE le stringhe in grassetto sopra?


4
@poly: Non era una "accusa", ma una domanda calma e normale che perfettamente può prendere un "no" come risposta. @ Joshua: Sì, alcune persone (non troppo poche) lasciano che questo sito faccia i compiti per loro. Ma fare domande per i compiti non è una brutta cosa da fare su SO, quando sono contrassegnati come tali. Di solito lo stile delle risposte cambia da "ecco la soluzione" a "ecco alcune cose a cui non hai pensato", e questa è una buona cosa. Qualcuno deve cercare di mantenere la distinzione, nel suo caso ero io, e altrove "altre persone" fanno la stessa cosa. È tutto.
Tomalak

13
Spero di non vedere mai una domanda come "Suona un po 'come una domanda sul posto di lavoro. Non è vero?" e poi le persone discuteranno se lo stack overflow sta facendo il lavoro di qualcuno.
marcio

@Joshua +1 rispetto alla soluzione regex che hai accettato, potresti dirmi come potrei sostituire le corrispondenze (duplicati) con un elemento della coppia (ad esempio, not that that is related-> not that is related)? Grazie in anticipo
Antoine

@ Joshua credo di aver trovato la soluzione: dovrei sostituirla con \1!
Antoine

2
@DavidLeal Che ne dici \b(\w+)\s+(\1\s*)+\b?
ytu

Risposte:


141

Prova questa espressione regolare:

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

Ecco \bun confine di parola e fa \1riferimento alla corrispondenza acquisita del primo gruppo.


1
Mi fa meraviglia; è possibile farlo \0anche tu ? (Dov'è \0l'intera regex, fino al punto corrente OR dove si \0riferisce all'intera regex)
Pindatjuh

@Pindatjuh: No, non credo perché anche quella sottoincontro farebbe parte dell'intera partita.
Gumbo

Almeno funziona sul motore regex utilizzato nella finestra di dialogo di ricerca / sostituzione di Eclipse.
Chaos_99

3
Solo un avvertimento, questo non gestisce le parole con apostrofi o (come dice Noel) trattini. La soluzione di Mike funziona meglio in questi casi

3
Inoltre, non cattura le triple (o più), non quando una delle doppie / triple si trova alla fine della stringa
Nico

20

Credo che questa regex gestisca più situazioni:

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

Una buona selezione di stringhe di test può essere trovata qui: http://callumacrae.github.com/regex-tuesday/challenge1.html


Ottimo, funziona con apostrofi / trattini / ecc. anche grazie!

per il collegamento challenge1, cosa collochi nell'area di sostituzione per utilizzare la parola raggruppata? Ho provato <strong>\0</strong>ma non funziona.
quartieri alti

2
Non cattura le triple (o più), non quando una delle doppie / triple si trova alla fine della stringa
Nico

@uptownhr che vuoi usare $1 <strong>$2</strong>. Ma usa anche espressioni regolari diverse /\b(\S+) (\1)\b/gi. Ecco un collegamento: callumacrae.github.io/regex-tuesday/…
dsalaj

e se voglio trovare tutte le parole consecutive da un particolare tag, <p class="bebe">bla bla</p>come posso integrare questa formula regex?
Solo io

7

Prova questo con sotto RE

  • \ b inizio del confine parola parola
  • \ W + qualsiasi carattere della parola
  • \ 1 stessa parola già trovata
  • \ b fine della parola
  • () * Ripetendo di nuovo

    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

La libreria PCRE ampiamente utilizzata può gestire tali situazioni (non otterrai lo stesso con i motori regex conformi a POSIX, però):

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

Hai bisogno di qualcosa per abbinare i caratteri tra le due parole, come \W+. \bnon lo farà, perché non consuma alcun carattere.
Alan Moore

Ciò risulterà potenzialmente in corrispondenza di falsi positivi in ​​casi come ... the these problems.... Questa soluzione non è affidabile come la struttura generale del modello di Gumbo che implementa sufficientemente i confini delle parole.
mickmackusa

e se voglio trovare tutte le parole consecutive da un particolare tag, <p class="bebe">bla bla</p>come posso integrare questa formula regex?
Solo io

4

Questa è la regex che uso per rimuovere le frasi duplicate nel mio twitch bot:

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

(\S+\s*) cerca qualsiasi stringa di caratteri che non sia uno spazio bianco, seguito da uno spazio vuoto.

\1{2,}quindi cerca più di 2 istanze di quella frase nella stringa da abbinare. Se ci sono 3 frasi identiche, corrisponde.


Questa risposta è fuorviante. Non caccia i duplicati, caccia le sottostringhe con 3 o più occorrenze. Inoltre, non è molto robusto a causa del \s*gruppo di cattura. Guarda questa dimostrazione: regex101.com/r/JtCdd6/1
mickmackusa

Inoltre, casi estremi (testo a bassa frequenza) produrrebbe corrispondenze false positive. Ad esempio I said "oioioi" that's some wicked mistressship!, oioioiesss
mickmackusa

4

L'espressione seguente dovrebbe funzionare correttamente per trovare un numero qualsiasi di parole consecutive. La corrispondenza può essere case insensitive.

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

Input di esempio: addio addio GooDbYe

Output di esempio: arrivederci

Spiegazione:

L'espressione regex:

\ b: Inizio di un confine di parola

\ w +: qualsiasi numero di caratteri alfanumerici

(\ s + \ 1 \ b) *: qualsiasi numero di spazio seguito da una parola che corrisponde alla parola precedente e termina il confine della parola. L'intera cosa racchiusa in * aiuta a trovare più di una ripetizione.

Raggruppamento:

m.group (0): conterrà il gruppo abbinato nel caso precedente Goodbye goodbye GooDbYe

m.group (1): conterrà la prima parola dello schema corrispondente nel caso precedente Goodbye

Il metodo di sostituzione sostituisce tutte le parole corrispondenti consecutive con la prima istanza della parola.


3

No. Questa è una grammatica irregolare. Potrebbero esserci espressioni regolari specifiche del motore / della lingua che puoi usare, ma non esiste un'espressione regolare universale che possa farlo.


12
Sebbene sia corretto in senso stretto, credo che non ci sia più un motore di regex in uso serio che non supporti il ​​raggruppamento e i riferimenti a ritroso.
Tomalak

3

Eccone uno che cattura più parole più volte:

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

e se voglio trovare tutte le parole consecutive da un particolare tag, <p class="bebe">bla bla</p>come posso integrare questa formula regex?
Just Me

Credo che richiederà l'analisi HTML. Per ogni dato tag che desideri cercare, trova tutte le occorrenze dei tag all'interno dell'HTML ed esegui questa regex una per una su ciascuna. Oppure, se non ti interessa dove avviene la ripetizione nell'HTML, concatena tutti gli attributi di testo del tag ed esegui la regex sulla stringa concatenata
synaptikon

Mi trovo la risposta<p class="bebe">.*?\b\s+(\w+)\b\K\s+\1\s+\b(?=.*?<\/p>)
Just Me

3

Regex per eliminare 2 o più parole duplicate (parole consecutive / non consecutive)

Prova questa regex che può catturare 2 o più parole duplicate e lasciare solo una singola parola. E le parole duplicate non devono nemmeno essere consecutive .

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

Qui, \bviene utilizzato per il confine di parole, ?=viene utilizzato per un lookahead positivo e \1viene utilizzato per i riferimenti all'indietro.

Fonte di esempio


1
Non consecutivo è una cattiva idea: "the cat sat on the mat"->" cat sat on the mat"
Walf

@Walf True. Tuttavia, ci sono scenari in cui ciò è inteso. (ad esempio: durante lo scraping dei dati)
Niket Pathak

Perché hai rotto di nuovo la tua regex dopo che l' ho corretta ? Pensavi che avessi cambiato il suo intento? Anche l'esempio che hai collegato non ha l'errore.
Walf

Sì, è stato un errore, copia incollata la roba sbagliata. Destinato a copiare quello dal mio esempio in realtà. comunque, ora funziona! quindi tutto bene! Grazie!
Niket Pathak

2

L'esempio in Javascript: The Good Parts può essere adattato per fare questo:

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

\ b usa \ w per i confini delle parole, dove \ w è equivalente a [0-9A-Z_a-z]. Se non ti dispiace questa limitazione, la risposta accettata va bene.


2

Poiché alcuni sviluppatori stanno arrivando su questa pagina alla ricerca di una soluzione che non solo elimini le sottostringhe duplicate consecutive non di spazi bianchi, ma anche triplicate e oltre, mostrerò il modello adattato.

Pattern: /(\b\S+)(?:\s+\1\b)+/( Pattern Demo )
Replace: $1(sostituisce la corrispondenza di stringa intera con il gruppo di cattura n. 1)

Questo modello corrisponde avidamente a una sottostringa "intera" senza spazi, quindi richiede una o più copie della sottostringa corrispondente che può essere delimitata da uno o più caratteri di spazio (spazio, tabulazione, nuova riga, ecc.).

In particolare:

  • \b I caratteri (confine di parola) sono fondamentali per garantire che le parole parziali non siano abbinate.
  • La seconda parentesi è un gruppo non di cattura, perché questa sottostringa di larghezza variabile non ha bisogno di essere catturata - solo abbinata / assorbita.
  • il +(uno o più quantificatori) sul gruppo che non cattura è più appropriato che *perché *"infastidirà" il motore di regex per catturare e sostituire le occorrenze singleton - questo è uno spreco di design.

* nota se hai a che fare con frasi o stringhe di input con punteggiatura, il modello dovrà essere ulteriormente perfezionato.


@AdamJones usa questo modello nel tuo progetto php. La risposta di Nico contiene una sintassi non necessaria.
mickmackusa

1

Questa espressione (ispirata da Mike, sopra) sembra catturare tutti i duplicati, i triplicati, ecc., Compresi quelli alla fine della stringa, che la maggior parte degli altri non fa:

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

Conosco la domanda posta per abbinare solo i duplicati , ma un triplo è solo 2 duplicati uno accanto all'altro :)

Per prima cosa, mi (^|\s+)assicuro che inizi con una parola intera, altrimenti "bistecca di bambino" andrebbe a "bistecca di bambino" (le "s" corrisponderebbero). Quindi, trova tutte le parole complete ( (\b\S+\b)), seguite da una fine di stringa ( $) o da un numero di spazi ( \s+), il tutto ripetuto più di una volta.

L'ho provato in questo modo e ha funzionato bene:

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

Ho problemi a riscriverlo in PHP, è fondamentale che riceva una singola copia del duplicato corrispondente sostituendo ogni occorrenza di duplicati / triplicati ecc. Finora ho: preg_replace ('/ (^ | \ s +) (\ S +) ( ($ | \ s +) \ 2) + / im ',' $ 0 ', $ stringa);
AdamJones

Questa è la migliore risposta. Ho appena apportato una modifica a questo aggiungendo \balla fine in questo modo: /(^|\s+)(\S+)(($|\s+)\2)+\b/g, "$1$2")Questo funzionerà per situazioni come questa: the the string String string stringing the the along the the stringdiventerà the string stringing the along the stringAvviso string stringing. Viene abbinato alla tua risposta. Grazie.
Ste

-1

Usalo nel caso in cui desideri controllare la presenza di parole duplicate senza distinzione tra maiuscole e minuscole.

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

L'uso del modificatore di pattern senza distinzione tra maiuscole e minuscole non è utile per il modello. Non ci sono intervalli di lettere per la bandiera da influenzare.
mickmackusa

Questo è effettivamente un duplicato della risposta accettata e non aggiunge alcun valore alla pagina. Considera l'idea di rimuovere questa risposta per ridurre il gonfiore della pagina.
mickmackusa
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.