2012-02-19 1 views
3

Я пытаюсь найти способ удалить все символы в первом слове, если этот символ находится во втором слове. Вход выглядит следующим образом:Как удалить символы из слова, если они также находятся в следующем слове (sed)?

компьютер стоил

И результат должен быть: «mpuer», потому что с, о и т были удалены. Существует несколько строк, разделенных возвратом, 2 слова разделены пробелом.

Я искал довольно долгое время для решения, но я действительно застрял. Вся помощь приветствуется.

+1

Я не думаю, что вы можете сделать это с помощью sed в одиночку - это было бы довольно просто с небольшим сценарием оболочки + sed или некоторым perl. – Flexo

+1

Это часть задания, поэтому я должен использовать sed самостоятельно. – Aaron

+1

['perl -lape '$ _ = $ F [0]; s/[{$ F [1]}] // g''] (http://ideone.com/M2fQg) – jfs

ответ

5

Это может работать для вас:

echo "computer cost" | 
sed ':a;s/\(.\)\(.* .*\1.*\)/\2/;ta;s/ .*//' 
mpuer 

Объяснение:

  • сделать ярлык для будущей команды филиала :a;
  • Удаление символа в первом слове, которое соответствует с тем же характером во втором слове s/\(.\)\(.* .*\1.*\)/\2/
  • Если замена произошла ветвь маркировать ta
  • Когда больше замен не удалить второе слово. s/ .*//

Замещение регулярное выражение может быть дополнительно объяснено:

  • \(.\) соответствует любому символу в слове один (впоследствии обозначаться как \1)
  • \(.* .*\1.*\) матчей любых символов в оставшейся части слова один .* за которым следует пробел , за которым следуют некоторые из двух символов в слове два .*, за которым следует соответствующий символ из первого слова \1, за которым следуют остальные символы f rom слово два .* эта группировка позже будет известна как \2.
  • Если вышеуказанные матчи заменить его \2, таким образом, эффективно удаляя соответствующий символ \1
+0

, она [работает] (http://ideone.com/TQ7GP), но выглядит сложной. – jfs

+0

Не могли бы вы объяснить команду sed –

+0

+1: Молодцы - но вы действительно должны объяснить, потому что это не очевидно. –

1

В основном вы делаете это tr;

echo computer cost | while read x y;do echo $x | tr -d $y ; done; 

, если у вас есть файл (words) как

computer cost 
computer mop 

Следующая команда делает замену.

while read x y; do echo $x | tr -d $y ; done< words 

Если вы хотите использовать sed просто заменить tr -d $y с sed s/[$y]//g

+1

Это часть задания, поэтому я должен использовать sed самостоятельно. – Aaron

+0

@Aaron см. Мое обновление (последняя строка) –

+1

Спасибо за ваше время, но я действительно ограничен, чтобы использовать sed '..'. Но я думаю, что нашел способ с регулярным выражением и цикл в sed. Я отправлю решение, если оно будет полностью работать. – Aaron

3

Это работает (как это делает solution по potong):

sed -e ': loop' \ 
    -e 's/\([a-z]*\)\([a-z]\)\([a-z]*\) \([a-z]*\2[a-z]*\)/\1\3 \4/' \ 
    -e 't loop' \ 
    -e 's/ .*//' \ 
    "[email protected]" 

Первая строка устанавливает метку.Третья строка относится к метке, если была успешная замена, поскольку строка была прочитана, и последний раз, когда был выполнен t, так что устанавливается цикл, в то время как команда-заменитель находит что-то делать. Последняя строка удаляет слово после пробела после завершения цикла.

Теперь все глаза концентрируются на регулярных выражениях. Ключевое понимание состоит в том, что вы можете искать повторение запоминаемого шаблона позже в строке, используя \n, где n - это цифра. Первая часть регулярного выражения разделяет линию на 5 частей. Первая часть - (возможно, пустая) последовательность букв, которые не интересны; вторая - интересная одна буква; третья - другая (возможно, пустая) последовательность букв, которые не интересны; четвертое - пространство, отделяющее первое слово от второго. Заключительную часть можно разделить на 3 части, хотя они все сгруппированы в одно захватывающее выражение. Он состоит из последовательности нулевых или более неинтересных букв, повторения интересной буквы от первого слова на линии (\2) и другой последовательности нулевых или более не интересных букв.

Сменная строка хранит до и после частей первого слова плюс пробел и второе слово.

В комбинации он находит каждую из букв c, o и t, в свою очередь, устраняя их от первого слова и оставляя их в покое во втором.

Условное разветвление в sed сложно в использовании, но оно может действительно забить. Когда ваши руки связаны таким назначением, это делает решение возможным.

$ al 'computer cost' 'encyclopedia brittanica' 'security privacy' | 
> sed -e ': loop; s/\([a-z]*\)\([a-z]\)\([a-z]*\) \([a-z]*\2[a-z]*\)/\1\3 \4/; t loop' 
mpuer 
eyloped 
seut 
$ 

al просто перечисляет свои аргументы одному в каждой строке - отсюда мнемонический список аргументов:

#include <stdio.h> 
int main(int argc, char **argv) 
{ 
    while (*++argv) 
     puts(*argv); 
    return 0; 
} 

решение Potong является по существу эквивалентна версии 'Code Golf' шахты:

sed ':a;s/\(.\)\(.* .*\1.*\)/\2/;ta;s/ .*//' 

Он использует ту же общую технику, что и моя, но упрощает регулярное выражение. Одним из упрощений является использование . (любой символ) вместо [a-z] (любая буква). Другой заключается в том, чтобы понять, что ведущая картина не имеет значения; он будет оставлен в покое. Последнее состоит в том, чтобы сгруппировать хвост первого слова со всем вторым. Оглядываясь назад, я мог бы (должен?) Добавить к моему шаблону якорь ^. Лейбл Потонг - это просто a.

+0

+1: за такое подробное объяснение. – potong