Perl - найти повторяющиеся строки в файле или массиве

Я пытаюсь напечатать дубликаты строк из файлового дескриптора, а не удалять их или что-либо еще, что я вижу, задаваемые по другим вопросам. У меня недостаточно опыта работы с Perl, чтобы быстро это сделать, поэтому я спрашиваю здесь. Какой способ сделать это?

4 ответа

Решение

Используя стандартные сокращения Perl:

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

Как "однострочник":

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

Больше данных? Это печатает <file name>:<line number>:<line>:

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

Объяснение %seen:

  • %seen объявляет хеш Для каждой уникальной строки на входе (которая исходит от while(<>) в этом случае) $seen{$_} будет иметь скалярный слот в хэше, названный по тексту строки (это то, что $_ делает в {} брекеты).
  • Использование постфиксного оператора приращения (x++) мы берем значение для нашего выражения, не забывая увеличивать его после выражения. Итак, если мы не "увидели" линию $seen{$_} не определено, но когда оно вводится в числовой "контекст", как это, оно принимается за 0- и ложь.
  • Затем он увеличивается до 1.

Итак, когда while начинает работать, все строки "ноль" (если это помогает, вы можете думать о линиях как "не %seen") тогда, когда мы впервые видим линию, perl принимает неопределенное значение - что не удается if - и увеличивает счетчик в скалярном интервале до 1. Таким образом, он равен 1 для любых будущих случаев, в которые он проходит if состояние и оно напечатано.

Теперь, как я сказал выше, %seen объявляет хеш, но с strict отключено, любое переменное выражение может быть создано на месте. Так что в первый раз Perl видит $seen{$_} он знает что я ищу %seenУ него его нет, поэтому он его создает.

Еще одна полезная вещь в этом заключается в том, что в конце, если вы хотите использовать его, у вас есть счетчик того, сколько раз каждая строка была повторена.

Попробуй это

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

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

Печатает дупс только один раз:

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

Если у вас Unix-подобная система, вы можете использовать uniq:

uniq -d foo

или же

uniq -D foo

должен делать то, что вы хотите. Больше информации: man uniq.

Другие вопросы по тегам