用sed替换等长的文本

时间:2013-04-14 23:32:31

标签: regex linux bash sed

有没有办法用sed替换其他东西等长的图案(例如点,零等)? 像这样:

maci:/ san$ echo "She sells sea shells by the sea shore" | sed 's/\(sh[a-z]*\)/../gI'
.. sells sea .. by the sea ..

“我”需要更新版本的sed来忽略大小写) 这很容易:以“sh”开头的单词被双点(..)取代,但我该如何制作 它是这样的:... sells sea ...... by the sea .....

有什么想法吗?干杯!

6 个答案:

答案 0 :(得分:7)

我怀疑你不能用标准的sed来做,但你可以用Perl或其他更强大的正则表达式处理它。

$ echo "She sells sea shells by the sea shore" |
> perl -pe 's/(sh[a-z]*)/"." x length($1)/gei'
... sells sea ...... by the sea .....
$

e修饰符表示替换模式是可执行的Perl脚本;在这种情况下,它重复字符.的次数与匹配模式中的字符重复次数。 g修饰符在整行中重复出现; i修饰符用于不区分大小写的匹配。 Perl的-p选项在-e选项指定的脚本(替换命令)中处理后打印每一行。

答案 1 :(得分:5)

这个awk-oneliner能为你完成这项工作吗?

awk '{for(i=1;i<=NF;i++)if($i~/^[Ss]h/)gsub(/./,".",$i)}1' file

使用您的数据进行测试:

kent$  echo "She sells sea shells by the sea shore"|awk '{for(i=1;i<=NF;i++)if($i~/^[Ss]h/)gsub(/./,".",$i)}1'
... sells sea ...... by the sea .....

答案 2 :(得分:4)

$ echo "She sells sea shells by the sea shore" |
awk '{
   head = ""
   tail = $0
   while ( match(tolower(tail),/sh[a-z]*/) ) {
      dots = sprintf("%*s",RLENGTH,"")
      gsub(/ /,".",dots)
      head = head substr(tail,1,RSTART-1) dots
      tail = substr(tail,RSTART+RLENGTH)
   }
   print head tail
}'
... sells sea ...... by the sea .....

答案 3 :(得分:4)

一个老问题,但我找到了一个很好的,相对较短的单行解决方案:

sed ':a;s/\([Ss]h\.*\)[^\. ]/\1./;ta;s/[Ss]h/../g'

通过在循环中一次替换一个字符来工作。

:a;开始循环

s/\([Ss]h\.*\)[^\. ]搜索sh后跟任意数量的. s(我们到目前为止已完成的工作),后跟非点或空格字符(我们将要替换的内容) )

/\1./;由我们已完成的工作替换为另一个.

ta;如果我们进行任何替换,循环,否则......

s/[Ss]h/../gsh替换为两个.并将其称为一天。

答案 4 :(得分:2)

正如其他人所说,sed并不适合这项任务。这当然是可能的,这里有一个例子,它适用于具有空格分隔词的单行:

echo "She sells sea shells by the sea shore" |

sed 's/ /\n/g' | sed '/^[Ss]h/ s/[^[:punct:]]/./g' | sed ':a;N;$!ba;s/\n/ /g'

输出:

... sells sea ...... by the sea .....

第一个'sed'用换行符替换空格,第二个用点击替换空格,第三个删除换行符为shown in this answer

如果您有不可预测的单词分隔符和/或段落,这种方法很快就会变得无法管理。

编辑 - 多行替代

这是处理多行输入的一种方法,受到 Kent的评论(GNU sed)的启发:

echo "
She sells sea shells by the sea shore She sells sea shells by the sea shore,
She sells sea shells by the sea shore She sells sea shells by the sea shore
 She sells sea shells by the sea shore She sells sea shells by the sea shore
" |

# Add a \0 to the end of the line and surround punctuations and whitespace by \n 
sed 's/$/\x00/; s/[[:punct:][:space:]]/\n&\n/g' |

# Replace the matched word by dots
sed '/^[Ss]h.*/ s/[^\x00]/./g' | 

# Join lines that were separated by the first sed
sed ':a;/\x00/!{N;ba}; s/\n//g'

输出:

... sells sea ...... by the sea ..... ... sells sea ...... by the sea .....,
... sells sea ...... by the sea ..... ... sells sea ...... by the sea .....
 ... sells sea ...... by the sea ..... ... sells sea ...... by the sea .....

答案 5 :(得分:2)

这可能适合你(GNU sed):

sed -r ':a;/\b[Ss]h\S+/!b;s//\n&\n/;h;s/.*\n(.*)\n.*/\1/;s/././g;G;s/(.*)\n(.*)\n.*\n/\2\1/;ta' file

本质上;它复制以shSh开头的单词,用.替换每个字符,然后将新字符串重新插入原始字符串。当搜索字符串的所有出现都已用尽时,它会打印出该行。