如何从Bash中的字符串中删除重复的字符?

时间:2014-05-01 05:52:18

标签: regex linux bash tr

我有一个字符串

cabbagee 

我想删除重复的字符。 如果我使用tr -s,它将删除序列中的重复字符。但我想要的输出是

cabge

感谢是否有人可以帮助我。

提供的答案是正确的,但我无法使用awk所以我使用了:

#!/usr/bin/bash
key=$1
len=${#key}
mkey=""
for (( c=0; c<len; c++ ))
do
    tmp=${key:$c:1}
    echo $mkey | grep $tmp >/dev/null 2>&1   
    if [ "$?" -eq "0" ]; then
        echo "Found $tmp in $mkey"
    else
        mkey+=$tmp
    fi
done
echo $mkey

5 个答案:

答案 0 :(得分:5)

您可以使用awk吗?

awk -v FS="" '{
    for(i=1;i<=NF;i++)str=(++a[$i]==1?str $i:str)
}
END {print str}' <<< "cabbagee"
cabge

其他几种方式:

gnu awk

awk -v RS='[a-z]' '{str=(++a[RT]==1?str RT: str)}END{print str}' <<< "cabbagee"
cabge

awk -v RS='[a-z]' -v ORS= '++a[RT]==1{print RT}END{print "\n"}' <<< "cabbagee"
cabge

gnu sedawk

sed 's/./&\n/g' <<< "cabbagee" | awk '!a[$1]++' | sed ':a;N;s/\n//;ba'
cabge

答案 1 :(得分:3)

您编辑了自己的帖子并发布了一个丑陋而破碎的答案。纯粹的Bash中更简单,更有效,更高效的方法:

#!/bin/bash

key=$1
mkey=$key
for ((i=0;i<${#mkey};++i)); do
    c=${mkey:i:1}
    tailmkey=${mkey:i+1}
    mkey=${mkey::i+1}${tailmkey//"$c"/}
done
echo "$mkey"

为什么你的脚本坏了?以下是一些你的失败而我的失败的情况。为了演示,我调用了您的脚本banana和我的gorilla。哦,因为我不是故意的,我修复了你的剧本所带来的琐碎的引用问题(用*字符轻易打破)并评论了洪水部分:

#!/usr/bin/bash
key=$1
len=${#key}
mkey=""
for (( c=0; c<len; c++ )); do
    tmp=${key:$c:1}
    echo "$mkey" | grep "$tmp" >/dev/null 2>&1   # Added quotes here!
    if [ "$?" -eq "0" ]; then
        : # echo "Found $tmp in $mkey" # Commented this to remove flooding
    else
        mkey+=$tmp
    fi
done
echo "$mkey"   # Added quotes here!

让我们走吧:

$ ./banana '^'

$ ./gorilla '^'
'^'

是的,因为^是grep正则表达式中使用的字符。类似的内容发生在$.

$ ./banana 'a.'
a
$ ./gorilla 'a.'
a.

现在反斜杠也会导致问题:

$ ./banana '\\'
\\
$ ./gorilla '\\'
\

(删除>/dev/null 2>&1部分以查看grep: Trailing backslash错误。同样的事情发生在[

没有提到你的脚本效率很低!它多次调用grep。在这方面,我的表现要好一些:

$ time for i in {1..200}; do ./banana cabbage; done &>/dev/null

real    0m3.028s
user    0m0.216s
sys     0m0.464s
$ time for i in {1..200}; do ./gorilla cabbage; done &>/dev/null

real    0m0.878s
user    0m0.172s
sys     0m0.324s

不错,嗯?

另一个能说明问题的基准:长字符串,例如Lorem Ipsum的一段:

$ time ./banana 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.'
Lorem ipsudlta,cngDSMqvhPbNAUfCI

real    0m1.464s
user    0m0.104s
sys     0m0.224s
$ time ./gorilla 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.'
Lorem ipsudlta,cng.DSMqvhPbNAUfCI

real    0m0.013s
user    0m0.000s
sys     0m0.008s

这是因为banana为输入字符串的每个字符调用grep,而gorilla动态执行删除。 (我不会提到banana错过了这段时间。)

答案 2 :(得分:0)

怎么样:

echo "cabbagee" | sed 's/./&\n/g' | perl -ne '$H{$_}++ or print' | tr -d '\n'

哪个收益率:

cabge

上面将您的字符串的字符拆分为单独的行(sed 's/./&\n/g'),然后使用一点perl魔法(信用unix tool to remove duplicate lines from a file)删除任何重复的行。最后,tr -d '\n'删除我们添加的换行符,以实现所需的输出。

可能需要根据您的具体目的对其进行一些修改,而且感觉非常糟糕,但它似乎完成了工作。

祝你好运。

答案 3 :(得分:0)

您可以使用grep -o .将每个字符与\n分开,然后只收集在bash中看不到的字符:

grep -o . <<<'cabbagee' | \
{ while read c; do [[ "$s" = *$c* ]] || s=$s$c; done; echo $s; }

答案 4 :(得分:-2)

我不确定你在做什么语言,但你总是可以让for循环来完成字符串。然后创建一个if循环说明如果yourstring.charAt(i).equals(yourstring.char(i + 1){replace(yourstring.char(i + 1),&#34;&#34;)} 所以基本上通过一个循环来说明当前索引处的字符是否等于下一个索引处的字符,然后用空字符串替换下一个索引:&#34;&#34;。