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.