如何删除重复的字符并仅在Perl中保留唯一的字符?

man*_*anu 11 regex string perl duplicates

如何删除重复的字符并仅保留唯一的字符.例如,我的输入是:

EFUAHUU
UUUEUUUUH
UJUJHHACDEFUCU
Run Code Online (Sandbox Code Playgroud)

预期产出是:

EFUAH
UEH
UJHACDEF
Run Code Online (Sandbox Code Playgroud)

我遇到perl -pe's/$1//g while/(.).*\/'的很棒,但它甚至可以删除输出中出现的单个字符.

cod*_*ict 15

这可以使用积极的前瞻来完成:

perl -pe 's/(.)(?=.*?\1)//g' FILE_NAME
Run Code Online (Sandbox Code Playgroud)

使用的正则表达式是: (.)(?=.*?\1)

  • . :匹配任何char.
  • 第一():记住匹配的单个字符.
  • (?=...) :+ ve预测
  • .*? :匹配两者之间的任何东西
  • \1 :记住的比赛.
  • (.)(?=.*?\1):匹配并记住任何字符串,如果它稍后再次出现在字符串中.
  • s/// :Perl做替换的方式.
  • g:全局替换...在第一次替换后不会停止.
  • s/(.)(?=.*?\1)//g :这将仅在字符串中稍后再次出现该字符时从输入字符串中删除char.

不会保持输入中char的顺序,因为对于输入字符串中的每个唯一char,我们保留其最后一次出现而不是一次出现.

为了保持相对顺序的完整性,我们可以KennyTM在其中一条评论中做到:

  • 反转输入线
  • 像以前那样进行替换
  • 在打印前反转结果

Perl的一行是:

perl -ne '$_=reverse;s/(.)(?=.*?\1)//g;print scalar reverse;' FILE_NAME
Run Code Online (Sandbox Code Playgroud)

由于我们print在反转后手动执行,因此我们不使用该-p标志,而是使用该-n标志.

我不确定这是否是最好的单行代码.如果他们有更好的选择,我欢迎其他人编辑这个答案.

  • 订单被更改(例如"EFAHU") - 想知道它是否重要. (2认同)
  • 这太棒了!!!! 但你能解释一下像===> s /(.)和(?=.*?\ 1)//正在做什么的一些细节?也可以按照我在早期查询中输入的顺序排列,例如.目前我正在接受EFAHU而不是EFUAH,这更有帮助.Thnax一吨:) (2认同)

gho*_*g74 5

如果Perl不是必须的,你也可以使用awk.这是针对awk发布的Perl one liners的有趣基准.对于具有300万++行的文件,awk快10秒以上

$ wc -l <file2
3210220

$ time awk 'BEGIN{FS=""}{delete _;for(i=1;i<=NF;i++){if(!_[$i]++) printf $i};print""}' file2 >/dev/null

real    1m1.761s
user    0m58.565s
sys     0m1.568s

$ time perl -n -e '%seen=();' -e 'for (split //) {print unless $seen{$_}++;}'  file2 > /dev/null

real    1m32.123s
user    1m23.623s
sys     0m3.450s

$ time perl -ne '$_=reverse;s/(.)(?=.*?\1)//g;print scalar reverse;' file2 >/dev/null

real    1m17.818s
user    1m10.611s
sys     0m2.557s

$ time perl -ne'my%s;print grep!$s{$_}++,split//' file2 >/dev/null

real    1m20.347s
user    1m13.069s
sys     0m2.896s
Run Code Online (Sandbox Code Playgroud)