#perl #line-processing
#perl #обработка строк
Вопрос:
Я пытаюсь напечатать повторяющиеся строки из дескриптора файла, а не удалять их или что-либо еще, что, как я вижу, задают по другим вопросам. У меня недостаточно опыта работы с perl, чтобы иметь возможность быстро это сделать, поэтому я спрашиваю здесь. Как это можно сделать?
Комментарии:
1. Многое зависит от размера входных данных, размеров строк и потенциального количества дубликатов. Если требования к памяти невелики, то решения с
%duplicates
хэшем являются адекватными.2. Они есть. Я просто использую дескриптор файла <DATA>, чтобы быстро что-то проверить. Не похоже, что есть какие-либо дубликаты, так что это хорошо.
Ответ №1:
Использование стандартных сокращений 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{$_}
будет скалярный слот в хэше, названный текстом строки (это то, что$_
делается в фигурных скобках has{}
).- Используя постфиксный оператор инкремента (
x
), мы берем значение для нашего выражения, не забывая увеличивать его после выражения. Итак, если мы не «видели», строка$seen{$_}
не определена — но при введении в числовой «контекст», подобный этому, она принимается за 0 — и false. - Затем значение увеличивается до 1.
Итак, когда while
начинает выполняться, все строки равны «нулю» (если это поможет, вы можете думать о строках как о «не %seen
«), затем, когда мы видим строку в первый раз, perl
принимает неопределенное значение — которое завершается ошибкой if
— и увеличивает счетчик в скалярном слоте до 1. Таким образом, это значение равно 1 для любых будущих вхождений, в этот момент оно выполняет if
условие и печатается.
Теперь, как я сказал выше, %seen
объявляется хэш, но при strict
выключенном режиме любое переменное выражение может быть создано на месте. Итак, когда perl видит в первый раз, $seen{$_}
он знает, что я ищу %seen
, у него этого нет, поэтому он создает это.
Дополнительным преимуществом этого является то, что в конце, если вы захотите его использовать, у вас есть подсчет того, сколько раз повторялась каждая строка.
Комментарии:
1. Можете ли вы объяснить, как именно работает $ seen{$_} ? Я понимаю, что он присваивает значение текущей строки хэш-таблице, но что здесь делает , который заставляет его находить дубликаты?
2. $seen{$_} ссылается на значение в хэше %seen с ключом $_, который является текущей строкой. Оператор увеличит значение хэша. Это означает, что при первом появлении ключа его значение будет равно false, и печать не произойдет. В последующие разы, когда это будет видно, оно будет > 0, и поэтому печать будет выполнена, а печать без аргументов по умолчанию печатает переменную $_ .
3. Ах, значит, ключом для хэша является строка, но значением является количество раз, когда она была найдена в файле -1.
4. ботаники perl впечатляют меня до чертиков. 2, если бы я мог!
Ответ №2:
попробуйте это
#!/usr/bin/perl -w
use strict;
use warnings;
my %duplicates;
while (<DATA>) {
print if !defined $duplicates{$_};
$duplicates{$_} ;
}
Комментарии:
1. Я бы сделал
print unless exists $duplicates{$_}
. И 1 для-w
,use strict
иuse warnings
.
Ответ №3:
Печатает дубликаты только один раз:
perl -ne "print if $seen{$_} == 1"
Комментарии:
1. Это похоже
sort file.txt | uniq -d
(печатать только дубликаты) на типичную оболочку Unix. Существует ли простой эквивалентsort file.txt | uniq -u
(печатать только уникальные строки)?
Ответ №4:
Если у вас Unix-подобная система, вы можете использовать uniq
:
uniq -d foo
или
uniq -D foo
должно делать то, что вы хотите. Дополнительная информация: man uniq.