2017-01-10 5 views
2

Die folgenden sed Schnipsel werden die doppelten Buchstaben im String und druckt nur die eindeutigen Buchstaben entfernen:Regulärer Ausdruck zu NUR doppelten Buchstaben in Zeichenfolge druckt

> echo "remove duplicate letters from string" | sed ':;s/\(.\)\(.*\)\1/\1\2/;t' 
> remov duplicatsfng 

Was wäre der reguläre Ausdruck die NUR drucken doppelte Buchstaben - so werden eindeutige Buchstaben verworfen (zB: v und d) und die mehr als einmal auftretenden Buchstaben sollten nicht in der Ausgabe wiederholt werden!

sollte das Ergebnis sein:

> remo lits 
+1

Mögliches Duplikat von [Regulärer Ausdruck für alle Zeichen, die mehr als 10 Mal wiederholt werden] (http://stackoverflow.com/questions/1660694/regular-expression-to-match-any-character-sing-repeated-more -than-10-mal) – Isaac

+0

Warum nicht einfach die Zeichenfolge durchlaufen und die Anzahl der Male zählen, die jedes Zeichen erscheint? –

+1

@Isaac: Das ist kein Duplikat. – Cyrus

Antwort

4

Sie können versuchen, mit GNU zu tun, dass sed: ersetzt dieser Teil jeder dupliziert:

sed -E ':a;s/(.)\1*(.+)\1+/\1\1\2/;ta;s/(((.)\3)*)./\1/g;s/.(.)/\1/g;' 

Details: für die Zeichenfolge "remove duplicate letters from string"

:a;s/(.)\1*(.+)\1+/\1\1\2/;ta; Buchstaben getrennt durch mindestens ein Zeichen mit zwei aufeinanderfolgenden Buchstaben. Ergebnis:

rreemmoov duplliicattssfng 

s/(((.)\3)*)./\1/g; dieses entfernt Buchstaben, die allein bleiben. Ergebnis:

rreemmoo lliittss 

s/.(.)/\1/g dieser entfernt aufeinanderfolgende Buchstaben. Ergebnis:

remo lits 

Mit Perl:

In einem mehr oder weniger ähnlich wie Sie so etwas schreiben können:

perl -pe's/(.)(?!.*\1)//g;while(s/(.)(.*)\1+/\1\2/g){}' 

Es ist kürzer, aber es ist wahrscheinlich effizienter, dies zu nutzen zweite Version mit dem Autosplit-Schalter und einem Hash, um die Anzahl der Vorkommen für jedes Zeichen zu zählen:

perl -F -ane'$h{$_}++ for(@F);for(@F){if($h{$_}>1){$h{$_}=1;print}}' 
+0

Beeindruckend. Es funktioniert nur mit GNU Sed, leider; BSD Sed unterstützt mit _extended_regexes ('-E') keine Rückverweise wie' \ 1' (in der Regex selbst, im Gegensatz zur Ersetzungszeichenfolge). – mklement0

+1

@ mklement0: Das OP scheint GNU sed zu verwenden, aber Sie können das gleiche mit Perl tun: 'perl -pe's/(.) (?!. * \ 1) // g; while (s/(.) (. *) \ 1 +/\ 1 \ 2/g) {} '' –

+1

@ mklement0: Ich werde ein wenig warten, bevor ich den Perl-Liner hinzufüge, weil ich nicht die Bestätigung habe, dass dies das ist, was das OP will, und Ich denke, es gibt wahrscheinlich intelligentere oder effizientere Wege, es mit Perl zu machen. –

1

Dies wird mit jedem awk auf jedem System arbeiten:

$ echo "remove duplicate letters from string" | 
awk '{ for (i=1;i<=length($0);) { chr=substr($0,i,1); if (gsub(chr,"") > 1) printf "%c", chr } print "" }' 
remo lits 
1

mit Posix sed (und Gnu)

echo "remove duplicate letters from string" | sed -e ':a' -e 's/\(\(.\).*\2.*\)\2/\1/;ta' -e "G;:b" -e '/^\(.\)\(.*\)\1\(.*\n.*\)/s//\1\2\3\1/;tb' -e 's/.//;/^\n/b e' -e 'b b' -e ':e' -e 's/.//' 

Konzept

  • Grenze Auftreten Brief an maximal zweimal ':a' -e 's/\(\(.\).*\2.*\)\2/\1/;ta'
  • fügen Sie eine neue Zeile (am Ende) mit Halter Pufferhinzu
  • Test, wenn erste Zeichen (vor einer zweiten Linie) zweimal dort sind, wenn ja er in einer zweiten Zeile setzen und das zweite Vorkommen des Buchstabens :b" -e '/^\(.\)\(.*\)\1\(.*\n.*\)/s//\1\2\3\1/;tb

  • entfernt erstes Zeichen s/.//

  • entfernen, wenn erstes Zeichen ist Newline, gehe zum Ende des Skripts, entferne den Zeilenumbruch (und drucke) /^\n/b e' ...-e ':e'
  • wenn nicht Schleife -e 'b b'
0

Dies könnte für Sie arbeitet (GNU sed):

sed -r ':a;s/\n*(([^\n]).*)\2/\n\1/;ta;s/\n(.)[^\n]*/\1/g' file 

Während Entfernen von doppelten Zeichen Präfix der Betroffenen mit einem einzigartigen Marker d.h \n. Entferne dann alle Zeichen, die nicht mit einem Marker (und auch Markern) assoziiert sind, um nur die Charaktere zu hinterlassen, die dupliziert haben.

+0

Ich mag diesen hier sehr, es scheint sehr logisch! –

Verwandte Themen