Ich suche nach einem regex
Muster, das dem dritten, vierten, ... Vorkommen jedes Zeichens entspricht. Schauen Sie unten zur Verdeutlichung:
Zum Beispiel habe ich die folgende Zeichenfolge:
111aabbccxccybbzaa1
Ich möchte alle duplizierten Zeichen nach dem zweiten Vorkommen ersetzen. Die Ausgabe wird sein:
11-aabbccx--y--z---
Einige Regex-Muster, die ich bisher ausprobiert habe:
Mit dem folgenden regulären Ausdruck kann ich das letzte Vorkommen jedes Zeichens finden: (.)(?=.*\1)
Oder mit diesem kann ich es für aufeinanderfolgende Duplikate tun, aber nicht für irgendwelche Duplikate: ([a-zA-Z1-9])\1{2,}
(.)(?<=^(?:(?:(?!\1).)*\1){2,}(?:(?!\1).)*\1)
Regex. Demo .(.)(?<=(.*\1){3})
?(.)(?<=(?:.*\1){3})
ich werde den Job auch machen, aber all dies ist nicht gut, da übermäßiges Backtracking Probleme mit längeren Strings verursachen kann. Ich würde lieber eine Nicht-Regex-Methode schreiben, um das Problem zu lösen.(.)(?<=(?:.*\1){3})
erhalte ich einen Leistungsunterschied, z. B. Ihr Muster 750ms, 25ms,(.)(?<=(?:\1.*?){2}\1)
3ms. Sie können sich einfach selbst testen. Ihr Muster scheint das am wenigsten effiziente zu sein, und es ist am schwersten zu lesen.Antworten:
Nicht-Regex-R-Lösung. Saite teilen. Ersetzen Sie Elemente dieses Vektors mit der Zeilen-ID> = 3 * durch
'-'
. Fügen Sie es wieder zusammen.*
rowid(x)
ist ein ganzzahliger Vektor, wobei jedes Element die Häufigkeit darstellt, mit der der Wert aus dem entsprechenden Element vonx
realisiert wurde. Also , wenn das letzte Elementx
ist1
, und das ist das vierte Mal1
in aufgetreten istx
, das letzte Elementrowid(x)
ist4
.quelle
Sie können dies leicht ohne Regex erreichen:
Siehe hier verwendeten Code
Ergebnis:
So funktioniert das:
for u in set(s)
Ruft eine Liste eindeutiger Zeichen in der Zeichenfolge ab:{'c','a','b','y','1','z','x'}
for i in ...
Schleifen über die Indizes, die wir in 3 sammeln.[i for i in range(len(s)) if s[i]==u][2:]
Durchläuft jedes Zeichen in der Zeichenfolge und prüft, ob es übereinstimmtu
(ab Schritt 1). Anschließend wird das Array vom 2. Element bis zum Ende aufgeteilt (wobei die ersten beiden Elemente gelöscht werden, falls vorhanden).s[:i]+'-'+s[i+1:]
- die Teilzeichenfolge bis zum Index mit-
und dann die Teilzeichenfolge nach dem Index verkettet wird , wobei das ursprüngliche Zeichen effektiv weggelassen wird.quelle
Eine Option mit
gsubfn
Daten
quelle
Kein Regex Python Einzeiler:
Dies zählt durch die Zeichenfolge auf, zählt das Vorkommen des aktuellen Zeichens dahinter und setzt das Zeichen nur, wenn es eines der ersten 2 ist, andernfalls einen Strich.
quelle
Ein anderer Weg, es mit zu tun
pandas
.Ausgabe :
quelle
Vielen Dank an Wiktor Stribiżew , Stefan Pochmann und Bobble Bubble . Der Vollständigkeit halber veröffentliche ich mögliche
regex
Lösungen, die in den Kommentaren erörtert werden.Dies ist nur mit einem regulären Ausdruck möglich, der das Lookbehind mit unendlicher Breite unterstützt. Mit dem Python PyPi Regex-Modul können wir Folgendes tun:
Snippet .
quelle