删除bash中的重复字符

删除bash中的重复字符

如果我有一行:

There are seven pencil

我想将其打印为:

Ther a svn pcil

bash shell 命令是什么?

澄清:目标是删除所有至少两次出现的字母(第一次出现除外)。

答案1

基于 sed 经典 Syntax s/replace-this/with-that/gwhereg意味着全局替换=所有发生,有人可以使用which2g而不是gwhich global replacement but after second occurence(这是一个gnu sed扩展)。

仅删除的示例e

$ echo $a
there are seven pencil

$ echo $a | sed 's/e//2g'
ther ar svn pncil

要删除所有重复的字母,我们可以使用这样的技巧:

$ sed -f <(printf 's/%s//2g\n' {a..z}) <<<"$a"
ther a svn pcil

不幸的是,这行不通:sed 's/[a-z]//2g'

上面的技巧使用了<( )可以用作文件的进程替换。

在我的解决方案中,过程替换被视为脚本文件,由option = read sed 命令从文件sed提供。sed-f

答案2

Awk解决方案(对于区分大小写的情况):

s="There are seven pencil"
printf '%s\n' "$s" | awk -v FS="" '{ 
           for(i=1; i<=NF; i++) 
               if ($i==" " || !a[$i]++) printf "%s", $i; print "" 
       }'
  • -v FS=""- 设置“空”字段分隔符,以便每个字符成为一个单独的字段(不是 POSIX,而是许多实现支持的 GNU 扩展)
  • for(i=1; i<=NF; i++)- 迭代字符
  • if ($i==" " || !a[$i]++)- 如果是空格字符或第一次出现某个字符

输出:

Ther a svn pcil

对于不区分大小写的情况,替换a[$i]a[tolower($i)].

答案3

这是 Bash 本身。

s="There are seven pencil"
declare -A A
while IFS= read -rn1 a; do
 [ -z "$a" ] || [ -n "${A[$a]}" ] && continue
 printf %s "$a"
 [ "$a" == " " ] || A[$a]=x
done <<<"$s"
echo

逐行解释:

  1. 将字符串分配给变量

    s="There are seven pencil"
    
  2. 声明一个关联数组A

    declare -A A
    
  3. 这个有点复杂。但没有详细信息,它按单个字符读取字符串并将刚刚读取的字符分配给a。这是一个while循环。

    while IFS= read -rn1 a; do
    
  4. 如果当前字符为空 ( [ -z "$a" ]) 或 ( ||) 如果与此键(此字符)关联的值已被设置(如果已设置,则此处出现),则继续循环(转到下一次迭代,因此读取下一个字符)再次,所以我们继续而不打印它)。

    [ -z "$a" ] || [ -n "${A[$a]}" ] && continue
    
  5. 打印当前字符。

    printf %s "$a"
    
  6. 如果字符是空格 - 那么不执行A[$a]=x- 这就是||这里的意思。A[$a]=x是关联操作。为了防止出现所有空格,不应为数组中的键空间分配任何值A。 (参见第 4 点。)

    [ "$a" == " " ] || A[$a]=x
    
  7. 这结束了while循环。<<<"$s"是这里字符串重定向。它用字符串填充循环。

    done <<<"$s"
    
  8. 最后echo打印行分隔符。printf在第 5 点中,仅打印字符。如果没有这个,echo输出将出现在与以下 shell 提示符相同的行上。把它取下来看看你自己。

    echo
    

答案4

另一个sed解决方案:

  • 对于单个字母字符:

    $ echo 'here hear' | sed 's/\(\([[:alpha:]]\).*\)\2/\1'
    here ear
    
  • 对于所有这些,该g标志都没有帮助,因为已经处理的字符不会再次检查。因此,使用循环 - 只要替换成功,“t”就会分支到标签

    $ echo There are seven pencils | sed -e :a -e 's/\(\([[:alpha:]]\).*\)\2/\1/; ta'
    Ther a svn pcil
    

    使用 GNU sed,您可以将其缩短为:

    sed -E ':a;s/(([[:alpha:]]).*)\2/\1;ta'
    

忽略大小写(仍然使用 GNU sed):

$ echo 'There this That' | sed -E ':a; s/(([[:alpha:]]).*)\2/\1/i; ta'
Ther is a


其中perl(此处仅限 ASCII 字母):

$ echo 'There are seven pencil' | perl -pe 'while(s/([a-zA-Z]).*?\K\1//g){}'
Ther a svn pcil
$ echo 'There this That' | perl -pe 'while(s/([a-z]).*?\K\1//gi){}'
Ther is a

相关内容