如果他们也在下一个字(sed)中,如何从字中删除字符?

我试图find一种方法来删除第一个单词中的所有字符,如果该字符在第二个单词中。 input如下所示:

电脑成本

结果应该是:“mpuer”,因为c,o和t被删除了。 有多行这样分隔的回车,这两个词是由一个空格分隔。

我一直在寻找相当一段时间的解决scheme,但我真的被卡住了。 所有的帮助表示赞赏。

这可能适合你:

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

说明:

  • 为将来的分支命令做一个标签:a;
  • 删除第一个单词中与第二个单词中s/\(.\)\(.* .*\1.*\)/\2/相同字符匹配的字符s/\(.\)\(.* .*\1.*\)/\2/
  • 如果发生替换分支到标签ta
  • 当没有更多的替代删除第二个字。 s/ .*//

替代正则表达式可以进一步解释:

  • \(.\)匹配单词1中的任何字符(以后称为\1
  • \(.* .*\1.*\)匹配一个单词的其余部分中的任何字符.*后跟一个空格 然后在第二个字母上有一个没有字符的字符.*接着是从第一个字符开始的匹配字符,然后是第二个字符剩下的字符。
  • 如果上面的匹配将其替换为\2从而有效地删除匹配字符\1

这工作(像potong的解决方案 一样 ):

 sed -e ': loop' \ -e 's/\([az]*\)\([az]\)\([az]*\) \([az]*\2[az]*\)/\1\3 \4/' \ -e 't loop' \ -e 's/ .*//' \ "$@" 

第一行建立一个标签。 第三行分支到标签,如果自从行被读取并且最后一次执行t已经有成功的替换,那么在替换命令找到要做的事情时建立一个循环。 循环完成后,最后一行删除空格后面的单词。

现在,所有的眼神都集中在正则表达式上。 关键的见解是,你可以在字符串后面使用\n来查找重复的记忆模式,其中n是一个数字。 正则表达式的第一部分将行分成5个部分。 第一部分是一个(可能是空的)不感兴趣的字母序列; 第二个是有趣的单个字母; 第三个是另一个(可能是空的)不感兴趣的字母序列; 第四个是把第一个词和第二个词分开的空间。 最后一部分本身可以细分为三部分,尽管它们都被组合成一个捕获表达式。 它由零个或多个不感兴趣的字母序列组成,重复来自该行上第一个单词( \2 )的有趣字母,以及另一个零个或多个不感兴趣的字母序列。

替换字符串保留第一个单词的前后部分,加上空格和第二个单词。

结合起来,它依次找到每个字母cot ,从第一个单词中消除它们,并将它们单独留在第二个单词中。

sed的条件分支是很难使用的,但它可以真正得分。 当你的双手被这样的任务所束缚时,这使解决方案变得可行。

 $ al 'computer cost' 'encyclopedia brittanica' 'security privacy' | > sed -e ': loop; s/\([az]*\)\([az]\)\([az]*\) \([az]*\2[az]*\)/\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/ .*//' 

它使用与我一样的通用技术,但简化了正则表达式。 一个简化就是使用. (任何字符)代替[az] (任何字母)。 另一个是认识到领先模式并不重要; 它将被单独留下。 最后是将第一个单词的尾部与第二个单词的尾部分组。 回想起来,我可以(应该?)为我的模式添加了一个锚点。 波东的标签简直就是a

基本上你是通过tr

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

如果你有一个文件( words )像

 computer cost computer mop 

以下命令将进行更换。

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

如果你想使用sed只需用sed s/[$y]//g替换tr -d $y