如何刪除重複的字符並僅保留唯一的字符。 例如,我輸入的是:如何刪除重複的字符並保留唯一的唯一一個在Perl中?
EFUAHUU
UUUEUUUUH
UJUJHHACDEFUCU
預期成果是:
EFUAH
UEH
UJHACDEF
我碰到perl -pe's/$1//g while/(.).*\/'
這是美好的,但它是消除即使在輸出字符的單個事件。
如何刪除重複的字符並僅保留唯一的字符。 例如,我輸入的是:如何刪除重複的字符並保留唯一的唯一一個在Perl中?
EFUAHUU
UUUEUUUUH
UJUJHHACDEFUCU
預期成果是:
EFUAH
UEH
UJHACDEF
我碰到perl -pe's/$1//g while/(.).*\/'
這是美好的,但它是消除即使在輸出字符的單個事件。
這可以使用positive lookahead來完成:
perl -pe 's/(.)(?=.*?\1)//g' FILE_NAME
中使用的正則表達式是:(.)(?=.*?\1)
.
:匹配任何炭。()
:記住匹配 單個字符。(?=...)
:+已經先行.*?
:以匹配\1
什麼:記住的比賽。(.)(?=.*?\1)
:匹配並記住 任何字符只有它再次出現 字符串中以後。s///
:做 替代的Perl的方式。g
:做替代 全球...這是後 第一個換人不停止。s/(.)(?=.*?\1)//g
:這將從 刪除輸入字符串 中的字符,只有當該字符在字符串中再次出現 時纔會出現。因爲在輸入字符串中的每個獨特的字符這將不保持在輸入字符的順序,我們保留其最後發生,而不是第一。
要保持相對順序不變,我們可以做什麼KennyTM
講述了一個評論:
這條Perl的一行是:
perl -ne '$_=reverse;s/(.)(?=.*?\1)//g;print scalar reverse;' FILE_NAME
由於我們在逆轉後手動執行print
,我們不使用-p
標誌,而是使用-n
標誌。
我不確定這是否是最好的單線程來做到這一點。如果他們有更好的選擇,我歡迎其他人編輯這個答案。
包含你列出一個名爲foo.txt的
python -c "print set(open('foo.txt').read())"
套在Python中沒有訂單......並且他想要Perl .. – ghostdog74 2010-04-06 06:27:46
他原來的文章沒有指定perl作爲需求(儘管他標記爲perl),只是指出他找到了perl作爲一種可能的方式來做到這一點。他也沒有說重要,只有唯一性。另外,使用單線表示該方法並不重要。 – jkyle 2010-04-06 15:53:11
領帶:: IxHash數據的文件是一個很好的模塊,用於存儲哈希順序(但可能是緩慢的,則需要基準,如果速度是重要的)。例如與測試:
use Test::More 0.88;
use Tie::IxHash;
sub dedupe {
my $str=shift;
my $hash=Tie::IxHash->new(map { $_ => 1} split //,$str);
return join('',$hash->Keys);
}
{
my $str='EFUAHUU';
is(dedupe($str),'EFUAH');
}
{
my $str='EFUAHHUU';
is(dedupe($str),'EFUAH');
}
{
my $str='UJUJHHACDEFUCU';
is(dedupe($str),'UJHACDEF');
}
done_testing();
perl -ne'my%s;print grep!$s{$_}++,split//'
這也正在工作,比前一個更短。我被這個迴應所淹沒:) 我想知道它的工作如果可能的話。 – manu 2010-04-06 09:27:43
它的工作方式與gianthare解決方案相同,但更加慣用的Perl和更快。 – 2010-04-07 05:50:35
一個不錯的,我同意。除了'my%s'外,幾乎只有一行。雖然我看不出加速是從哪裏來的。可能來自新的哈希表而不是重置?或者grep比顯式循環更有效率? – 2010-04-08 09:43:11
從貝,這個工程:
sed -e 's/$/<EOL>/ ; s/./&\n/g' test.txt | uniq | sed -e :a -e '$!N; s/\n//; ta ; s/<EOL>/\n/g'
在口頭上:標記每個換行符用<EOL>
字符串,然後把每一個人物在自己的行,然後使用uniq
刪除重複的行,然後刪除所有換行符,然後放回換行符而不是<EOL>
標記。
,我發現在一個論壇帖子的-e :a -e '$!N; s/\n//; ta
一部分,我不明白的單獨-e :a
部分或$!N
部分,因此,如果任何人都可以解釋這些,我會很感激。
嗯,那個只有連續重複;消除所有重複,你可以這樣做:
cat test.txt | while read line ; do echo $line | sed -e 's/./&\n/g' | sort | uniq | sed -e :a -e '$!N; s/\n//; ta' ; done
,雖然使人物在每一行按字母順序排列。
這看起來像積極lookbehind的經典應用程序,但不幸的是perl不支持。事實上,我認爲這樣做(將字符串中的前一個字符與長度不確定的完整正則表達式匹配)只能用.NET正則表達式類來完成。
然而,正向前查找支持完整的正則表達式,因此,所有你需要做的是反向的字符串,應用正前瞻(如unicornaddict說):
perl -pe 's/(.)(?=.*?\1)//g'
和扭轉回來,因爲沒有相反的是」只會將重複的字符保留在一行中的最後一個地方。
MASSIVE編輯
我已經花了最後半在這一個小時,這看起來像這樣的作品,沒有倒車。
perl -pe 's/\G$1//g while (/(.).*(?=\1)/g)' FILE_NAME
我不知道是否感到自豪或恐懼。我基本上是做正looakahead,然後用指定的\ G替換字符串 - 這使正則表達式引擎從匹配的最後一個匹配的位置開始匹配(由pos()變量內部表示)。
隨着測試輸入這樣的:
aabbbcbbccbabb
EFAUUUUH
ABCBBBBD
DEEEFEGGH
AABBCC
輸出是這樣的:
ABC
EFAUH
ABCD
DEFGH
ABC
我認爲它的工作...
說明 - 好吧,如果我的解釋最後一次是不夠清晰 - 超前會去停在重複變量的最後一場比賽[在代碼中,你可以做一個print pos();在循環內部檢查]和s/\ G // g將會刪除它[你確實不需要/ g]。因此在循環中,替換將繼續刪除,直到所有這樣的重複都被刪除。當然,這對你的口味來說可能有點過於集中處理,但大多數基於正則表達式的解決方案也是如此。不過,倒車/前瞻方法可能會比這更有效率。
更確切地說,它是*可變長度* lookbehinds Perl不支持。除.NET之外,它們還受到JGSoft(EditPad Pro,PowerGrep)的支持,並且受到Java的限制。 – 2010-04-06 11:51:24
編輯並添加新的解決方案。不知道它是否是全面的咖啡因...太多的咖啡因。 :-P – 2010-04-06 13:44:45
使用uniq的從List::MoreUtils:
perl -MList::MoreUtils=uniq -ne 'print uniq split ""'
如果設定可能遇到的字符被限制,例如只有字母,那麼最簡單的解決方案將與tr
perl -p -e 'tr/a-zA-Z/a-zA-Z/s'
它將自行替換所有字母,其他字符不會受到影響和/ s修飾符將擠壓重複出現的同一字符(替換後),從而刪除重複項
我壞 - 它只消除相鄰的外觀。無視
這裏是一個解決方案,我認爲應該比前瞻工作更快,但不是基於正則表達式的並使用散列表。
perl -n -e '%seen=();' -e 'for (split //) {print unless $seen{$_}++;}'
它分割的每一行轉換爲字符和僅打印所述第一外觀通過計數內部%外觀可見散列表
use strict;
use warnings;
my ($uniq, $seq, @result);
$uniq ='';
sub uniq {
$seq = shift;
for (split'',$seq) {
$uniq .=$_ unless $uniq =~ /$_/;
}
push @result,$uniq;
$uniq='';
}
while(<DATA>){
uniq($_);
}
print @result;
__DATA__
EFUAHUU
UUUEUUUUH
UJUJHHACDEFUCU
輸出:
EFUAH
UEH
UJHACDEF
如果Perl是不是必須的,你也可以使用awk。這裏是針對awk發佈的Perl一行內容的有趣基準。 awk對於具有3百萬++行的文件要快10秒以上
$ wc -l <file2
220
$ 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
+1,不錯的工作:) – codaddict 2010-04-08 07:42:33
我很驚訝正則表達式解決方案的速度有多快 – 2010-04-08 09:47:06
訂單已更改(例如「EFAHU」) - 是否重要。 – 2010-04-06 06:59:34
@Gavin:可以通過最初反轉字符串來修復,並在更換後反轉字符串。 – kennytm 2010-04-06 07:28:04
這是驚人的! 但你能解釋一下我的細節,比如 什麼===> s /(。)和(?=。*?\ 1)//正在做什麼? 也有可能有我已經在我的早期查詢中提出的相同的順序,例如。目前我得到的是EFAHU而不是EFUAH,這更有幫助。 Thnax一噸:) – manu 2010-04-06 08:24:50