Как удалить символы из слова, если они также находятся в следующем слове (sed)? - PullRequest
3 голосов
/ 19 февраля 2012

Я пытаюсь найти способ удалить все символы в первом слове, ЕСЛИ этот символ находится во втором слове.Входные данные выглядят так:

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

И результат должен быть: "mpuer", потому что c, o и t были удалены.Есть несколько таких строк, разделенных возвратом, 2 слова разделены пробелом.

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

Ответы [ 3 ]

6 голосов
/ 19 февраля 2012

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

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

Объяснение:

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

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

  • \(.\) соответствует любому символу в слове один (позже упоминается как \1)
  • \(.* .*\1.*\) соответствует любым символам в оставшейся части слова one .*, за которым следует пробел , за которым следуют некоторые символы, отсутствующие в слове two .*, за которыми следует соответствующий символ из слова one \1, за которым следуетпо оставшимся символам из слова два .* эта группировка будет позже известна как \2.
  • Если приведенные выше совпадения заменить на \2, эффективно удаляя соответствующий символ \1
3 голосов
/ 19 февраля 2012

Это работает (как и решение от 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/ .*//' \
    "$@"

Первая строка устанавливает метку. Третья строка разветвляется на метку, если с момента чтения строки произошел успешный заменитель, и при последнем выполнении 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;
}

Решение Потонга по сути эквивалентно моей версии Code Golf:

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

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

1 голос
/ 19 февраля 2012

В основном вы делаете это 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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...