unix-删除(i)单个字符之间的空白和(ii)一个单词的X个以上连续实例

时间:2018-11-09 19:03:36

标签: unix awk sed

我想

(i)仅当这些字符为单个时才替换字符之间的空格;即例如

Down [Enter] p s -- a u x [Delete] 

应该成为

Down [Enter] ps -- aux [Delete] 

(ii)删除连续重复超过X次的单词,直到出现任何其他不是单词的事物为止,以便(例如X = 2)

 [Delete] [Delete] [Delete] [Delete] [Delete] [Delete] ab inition [Delete] [Delete] [Delete] [Delete] [Delete] [Delete] ab definitio

成为

 [Delete] [Delete] ab initio [Delete] [Delete] ab definitio

谢谢!

1 个答案:

答案 0 :(得分:0)

您没有得到很多答复。我认为主要原因是两个不同问题的组合,这两个问题都不是简单的。通常,它有助于显示您自己的努力,但是我理解您的努力可能已经花了几个小时“从哪里开始”了。

第一个问题,删除单个字符之间的空格,可以通过sed中的循环来完成:

echo 'Down [Enter] p s -- a u x [Delete] ' | 
   sed -r ':a;s/( [^ ]|\r) ([^ ])( |$)/\1\2\r\3/;ta; s/\r//g'
Down [Enter] ps -- aux [Delete]

说明: 使用直接方法,a u x将在第一次替换后更改为au x,而其他空间将被忽略。您需要多次进行替换,并记住u中的字母au x是原始字符串中的单例。
为了记住已完成替换的位置,我们使用\r(稍后将其删除)。

:a;标签以返回下一次替换。
( [^ ]|\r)后接字母或我们临时的\r标记的空格
([^ ])后接字母的空格
( |$)空格或行尾
/\1\2\r\3/用两个记住的字符代替,当它不是该行的最后一个字符时,插入一个特殊标记和一个空格。
ta替换后返回到循环开始标记:a
s/\r//g'删除我们的临时标记。

第二个问题也很困难。下一个解决方案很接近但不正确:

for (( X=2; X<8; X++)); do
  echo "X=$X (incorrect solution)"
  echo 'some some some some some some some some some some some input' |
     sed -r 's/([^ ]+[ ]+)(\1{'${X}'})(\1+)/\2/g'
done

问题是当重复的字符串也出现在另一个位置时,如
some some some input some some some或更糟糕的some some some input input input

我看不到sed解决方案的简单修补,但是awk在这里会有所帮助。
为了计算重复的字段,我的解决方案是将每个单词视为一条记录。

for (( X=2; X<8; X++)); do
   echo "X=$X"
   echo 'some some some some some some some some some some some input some some some some' |
      awk -v x=$X 'BEGIN {RS="[ \n]"; ORS='\n'; repeated=1}
         { if (last==$0)
             repeated++;
           else
             repeated=1;
         }
         {last=$0}
         repeated <= x {print $0" "}
         END {print "\n"}
      '
done