我有一个字符串aaabefhhhhhthkkd
,我只需要从中提取非重复字母作为输出,保留顺序。
该字符串可以包含大写或小写字母。
输入:
aaabefhhhhhthkkd
输出:
beftd
需要如何定义这个逻辑才能获得上述所需的输出?
我尝试使用这个命令,但它只对我部分有用:
echo "aaabefhhhhhthkkd" | sed 's/./&\n/g' | uniq
上述部分运行命令的输出:
a
b
e
f
h
t
h
k
d
要测试的示例字符串:
String 1: aaabefhhhhhthkkd -> Output -> beftd
String 2: AAAbefhhhhhThkkD -> Output -> befTD
String 3: AAAbefhMThkkD -> Output -> befMTD
答案1
uniq
仅适用于相邻的重复项 - 因此如果您想使用它,您需要首先对输入进行排序,例如:
fold -w1 | sort | uniq -u | paste -sd ''
fold -w1
与你的相同sed 's/./&\n/g'
,但不会引入额外的虚假换行符sort
使重复的字符相邻uniq -u
-u
仅打印单例很重要paste -sd ''
将结果连接回一行
由于排序的原因,您将无法在所有情况下获得所需的输出顺序。
$ echo 'AAAbefhMThkkD' | fold -w1 | sort | uniq -u | paste -sd ''
DMTbef
如果您不想推出自己的解决方案,您可以随时使用 Perl 的MoreUtils
:
$ echo 'AAAbefhMThkkD' |
perl -MList::MoreUtils=singleton -ne 'print singleton split //'
befMTD
答案2
在每个 UNIX 机器上的任何 shell 中使用任何 awk:
$ echo 'aaabefhhhhhthkkd' |
awk '{
lgth = length()
for (pos=1; pos<=lgth; pos++) {
let = substr($0,pos,1)
if ( gsub(let,"&") == 1 ) {
printf "%s%s", let, (pos<lgth ? "" : ORS)
}
}
}'
beftd
答案3
awk '
{
n=split($0, a, "")
for(i=1; i<=n; i++){
if(gsub(a[i], "") == 1){ printf("%s", a[i]) }
}
print ""
}'
n=split($0, a, "")
:a[1]
成为字符串的第一个字符,a[2]
第二个等n
是字符总数。for(i=1; i<=n; i++)
:让我们循环遍历所有数组a
。if(gsub(a[i], "") == 1)
:删除a[i]
字符串中的所有字符。如果字符串中只删除了一个字符,printf("%s", a[i])
打印该字符。
print ""
处理完所有行后打印换行符。如果您只有一条输入线,则这是可选的。
压缩单行的示例:
$ awk '{n=split($0,a,"");for(i=1;i<=n;i++)if(gsub(a[i],"")==1)printf("%s",a[i])}' <<< AAAbefhMThkkD
befMTD
注意:POSIX 未定义按空字符串进行拆分。然而,gawk
(GNU Awk),mawk
和original-awk
全部按要求执行操作。
答案4
主题的变化
echo 'aaabefhhhhhthkkd' |
awk '{while (length()>0) {t=substr($0,1,1); printf (gsub( t ,"")==1)?t:""} print}'
beftd
$0
通过将第一个字符替换为直到空来进行消耗""
,并在仅发生一次替换时打印。