2017-01-10 1 views
2

Следующая СЭД фрагмент удаляет дублированные буквы в строке и печатать только уникальные письма:Регулярное выражение для печати только повторяющиеся буквы в строке

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

Что бы регулярное выражение для печати только повторяющиеся буквы - таким образом, уникальные буквы отбрасываются (например: v и d), и буквы, появляющиеся более одного раза, не должны повторяться на выходе!

Результат должен быть:

> remo lits 
+1

Возможный дубликат [Регулярное выражение для повторения любого символа более 10 раз] (http://stackoverflow.com/questions/1660694/regular-expression-to-match-any-character-being-repeated-more -than-10-times) – Isaac

+0

Почему бы просто не перебирать строку и не подсчитывать количество раз, когда появляется каждый символ? –

+1

@ Исаак: Это не дубликат. – Cyrus

ответ

4

Вы можете попробовать сделать это с помощью GNU СЭД:

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

детали: для строки "remove duplicate letters from string"

:a;s/(.)\1*(.+)\1+/\1\1\2/;ta;: эта часть заменяет каждый дублируется буквы, разделенные хотя бы одним символом двумя последовательными буквами. Результат:

rreemmoov duplliicattssfng 

s/(((.)\3)*)./\1/g; это один удаляет письма, которые остаются в одиночестве. Результат:

rreemmoo lliittss 

s/.(.)/\1/g это один удаляет последовательные буквы. Результат:

remo lits 

С Perl:

В более или менее одинаковым образом, вы можете написать что-то вроде этого:

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

Это короче, но это, вероятно, более эффективно использовать этот вторая версия с автосбросом и хеш для подсчета количества вхождений для каждого символа:

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

Впечатляющий. К сожалению, он работает только с GNU Sed; BSD Sed с переменными _extended_ ('-E') не поддерживает обратные ссылки, такие как' \ 1' (в самом регулярном выражении, а не в заменяющей строке). – mklement0

+1

@ mklement0: OP, похоже, использует GNU sed, но вы можете сделать то же самое с perl: 'perl -pe's/(.) (?!. * \ 1) // g; while (s/(.) (. *) \ 1 +/\ 1 \ 2/g) {} '' –

+1

@ mklement0: Я подожду немного, прежде чем добавлять perl один лайнер, потому что у меня нет подтверждения, что это то, чего хочет OP, и Я думаю, что есть, вероятно, более умные или более эффективные способы сделать это с помощью Perl. –

1

Это будет работать с любым AWK на любой системе:

$ 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

с POSIX SED (и ГНУ)

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/.//' 

концепт

  • предел вхождение буквы до максимума дважды ':a' -e 's/\(\(.\).*\2.*\)\2/\1/;ta'
  • добавить новую строку (в конце) с помощью держателя буфера G
  • тест, если первый символ есть в два раза (до второй линии), если да, то поставить его на второй линии и удалите вторую вхождение буквы :b" -e '/^\(.\)\(.*\)\1\(.*\n.*\)/s//\1\2\3\1/;tb

  • удалить первый символ s/.//

  • если первый символ - новая строка, перейдите к концу скрипта, удалите новую строку (и распечатайте) /^\n/b e' ...-e ':e'
  • если не петля -e 'b b'
0

Это может работать для вас (GNU СЭД):

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

В то время как удаление дубликатов символов префикс заинтересованных лиц, с уникальным маркером \n т.е.. Затем удалите все символы, не связанные с маркером (и маркерами тоже), чтобы оставить только те символы, у которых были дубликаты.

+0

Мне очень нравится, это кажется очень логичным! –