2011-05-04 21 views
6

我試圖從文件句柄打印重複行,而不是刪除它們或任何其他問題。我沒有足夠的perl經驗來快速做到這一點,所以我在這裏問。有什麼辦法做到這一點?Perl - 查找文件或數組中的重複行

+2

這在很大程度上取決於輸入的大小,線的尺寸和重複的潛在數量。如果內存要求很低,那麼帶有'%duplicates'哈希值的解決方案就足夠了。 – 2011-05-04 13:57:41

+0

他們是。我只是使用文件句柄來快速檢查某些內容。它看起來沒有任何重複,所以這很好。 – Chris 2011-05-04 14:00:25

回答

22

使用標準的Perl速記:

my %seen; 
while (<>) { 
    print if $seen{$_}++; 
} 

作爲 「單行」:

perl -ne 'print if $seen{$_}++' 

更多數據?這將打印<file name>:<line number>:<line>

解釋 %seen
perl -ne 'print ($ARGV eq "-" ? "" : "$ARGV:"), "$.:$_" if $seen{$_}++' 

  • %seen聲明哈希值。對於輸入中每個唯一的行(在這種情況下來自while(<>)$seen{$_}將在由該行的文本命名的散列(這是{}大括號中正在執行的操作)中具有標量槽。
  • 使用後綴增量運算符(x++)我們採取我們表達的價值,表達後記住要增量它。所以,如果我們還沒有「看到」$seen{$_}行是未定義的 - 但是當強制進入像這樣的數字「上下文」時,它被視爲0-和false
  • 那麼它遞增到1

所以,當while開始運行,所有線路都是「零」(如果它可以幫助你能想到的線路爲「不%seen」),那麼,第一我們看到一條線的時間,perl取未定義的值 - 這不符合if - 並將標量插槽的計數增加到1.因此,對於未來發生的任何事件,它通過if條件並將其打印爲1。

現在正如我上面所說的,%seen聲明瞭一個散列,但是關掉strict,任何變量表達式都可以在現場創建。所以第一次perl看到$seen{$_}它知道我在尋找%seen,它沒有它,所以它創建它。

對此的一個補充說明,最後,如果您喜歡使用它,您可以計算每行重複的次數。

+0

+1不錯的單行文本 – mcgrailm 2011-05-04 13:58:22

+0

你能解釋一下$ $ {$ _} ++是如何工作的嗎?我知道它將當前行的值賦給一個散列表,但是在這裏做的++是什麼使它找到重複的? – Chris 2011-05-04 14:08:30

+1

$ seen {$ _}引用哈希%中的一個值,鍵是$ _,它是當前行。 ++運算符將增加散列值。這意味着,第一次出現密鑰時,其值將是錯誤的,並且不會發生打印。隨後出現的時間將會大於0,因此打印將執行,默認情況下不打印參數的情況下打印$ _變量。 – TLP 2011-05-04 14:23:26

3

試試這個

#!/usr/bin/perl -w 
use strict; 
use warnings; 

my %duplicates; 
while (<DATA>) { 
    print if !defined $duplicates{$_}; 
    $duplicates{$_}++; 
} 
+0

我會'打印,除非存在$ duplicates {$ _}'。對'-w'使用+1,'使用strict'和'使用警告'。 – Blrfl 2011-05-04 19:50:15

0

如果你有一個類Unix系統,你可以使用uniq

uniq -d foo 

uniq -D foo 

應該做你想要什麼。更多信息:man uniq

2

打印愚弄只有一次:

perl -ne "print if $seen{$_}++ == 1" 
+1

這就像'sort file.txt | uniq -d'(只能打印重複)在典型的Unix shell中。有沒有一個簡單的等價的'sort file.txt | uniq -u'(僅打印唯一行)? – 2013-07-15 21:07:00