uniq файл CSV, игнорирующий столбец, awk, возможно?

Можно использовать perlнулевая ширина оглядывается regex синтаксис.

perl -pe "s/(?<=[aeiou])([^aeiou_]*)[aeiou]([^aeiou_]*)/\1\2/ig"

Этот следующий отрывок рассматривает входную строку как единственную строку (не несколько подстрок).

perl -pe "s/(?<=[aeiou])([^aeiou]*)[aeiou]/\1/ig"

7
18.09.2013, 00:56
4 ответа

С awk, Вы могли сделать:

awk -F, -vOFS=, '{l=$0; $3=""}; ! ($0 in seen) {print l; seen[$0]}'
18
27.01.2020, 20:13
  • 1
    , ничего себе, изящный и простой (и быстро, вероятно, также с помощью поисков хеша для сравнения предыдущей строке (строкам)). Однако это также не удаляет дубликаты, происходящие после чего-то промежуточного? (т.е., по-другому по сравнению с "uniq были выполнены на файле [если 3-й столбец удалил]" как OP, который спрашивают? т.е.: line1 = "x, a, 001, b, c, d, y", затем line12 = "x, a, 999, b, c, d, y" не появился бы с Вашим решением, но (возможно) должен?) –  Olivier Dulac 17.09.2013, 19:25
  • 2
    Вы правы, что это удаляет строки после чего-то промежуточного, и Вы правы, что uniq не сделал бы этого. Но если бы Вы смотрите на OP, он, кажется, полагал, что uniq действовал бы способ, которым делает этот сценарий, таким образом, этот сценарий, вероятно, что он на самом деле хотел. –  The Spooniest 17.09.2013, 19:31
  • 3
    @TheSpooniest: хороший, затем определенно +1 Stephane для прочтения XYProblem ^^ –  Olivier Dulac 17.09.2013, 19:48

Самый простой путь:

sort -u -t, -k1,2 -k4
  • -u: вывод только первая строка равняется
  • -t,: используйте запятую в качестве разделителя полей
  • -k1,2 -k4: вид только на полях 1,2 и 4 и остальных

Другая опция перестраивает данные с sed (отметьте опцию GNU -r) с обеих сторон - это требует, чтобы записи были главным образом фиксированной длиной, иначе она собирается перестать работать (и только едва заметно):

sed -r       's/^([^,]+,[^,]+)(,[^,]+)(.*)$/\1\3\2/' \
    | sort \
    | uniq -w 12 \
    | sed -r 's/^([^,]+,[^,]+)(.*)(,[^,]+)$/\1\3\2/'

Вы могли бы хотеть добавить другого sort в конце для упорядочивания его числами, при желании (используют -k опция выбрать согласно тому, как что вид должен быть выполнен - т.е. что-то sed -k3 -t,)

В Perl Вы могли, например, использовать части, на которых Вы хотите решить уникальность как ключи в хеше (значения сплошные линии) и вставить в хеш, только если ключ еще не определяется. Это, конечно, будет намного более гибко, чем использование sed (или awk), но также и больше записи (я далек от Гуру Perl, таким образом, вероятно, что это может быть сделано намного более изящным способом - см. другие ответы для подобных Perl решений для Perl):

#!/usr/bin/perl
use strict;

my %lines;
while (<>) {
    (my $k1, my $v, my $k2) = /^([^,]+,[^,]+,)([^,]+)(,.*)$/;
    my $k = $k1 . $k2;
    if (!exists($lines{$k})) {
        $lines{$k} = $_;
    }
}

for my $k (sort(keys(%lines))) {
    print $lines{$k};
}
7
27.01.2020, 20:13
  • 1
    Спасибо, к сожалению, поля не являются зафиксированной шириной. Я обновил вопрос, извинения. Ваш пример не работает над моей системой или для старого или для пересмотренного тестового сценария :( –  jon 17.09.2013, 13:44
  • 2
    , удаляя мой ответ и upvoting Ваш - кажется, примерно реализует алгоритм, который я описал. я, вероятно, использовал бы разделение, а не regexp для полевого извлечения, и это будет намного более просто только с $lines{$k} = $_ unless $lines{$k}; –  cas 17.09.2013, 14:15
  • 3
    Brilliant, +1! Я пытался сделать это с uniqполевые опции и не могли, не думал для использования sort -u. По тому, как я думаю это sort -u расширение GNU, не POSIX, но это будет хорошо работать в системах Linux. –  terdon♦ 17.09.2013, 20:41
  • 4
    @terdon я думаю, что Вы правы, что это - расширение. –  peterph 17.09.2013, 20:45
  • 5
    Хорошее и изящное решение! ( perl один) Однако как общий новобранец Perl, это потребовало, чтобы я немного прочитайте руководство понял то, что Вы делали здесь. %lines (легко распознаваемый его знаком процента), ассоциативный массив (иначе, "хешируют переменную" в малопонятном жаргоне Perl), который может принять "реальные" строки как ключевые идентификаторы, не просто индексы. Это - элемент, ответственный за все это удивительное "волшебство", сделанное здесь. –  syntaxerror 09.08.2015, 14:42

Способ сделать это с awk | sort | uniq | awk:

awk -F, '{a=$1;$1=$3;$3=a;print}' file | sort -k 2 | uniq -f 1 | awk -v OFS=',' '{a=$1;$1=$3;$3=a;print}'
3
27.01.2020, 20:13

Более простой Perl путь был бы:

perl -F"," -ane '$a=join(",",@F[0,1,3 .. $#F]); print unless $k{$a}; $k{$a}++' file

-a поля разделений в @F массив и -F"," устанавливает разделитель полей на ,. -n средства запускают скрипт, данный -e на каждой строке входного файла.

Идея состоит в том, чтобы взять часть массива (элементы 0,1 и 3 до конца массива), присоединиться к ним в строку ($a) и используйте ту строку в качестве хеша (ассоциативный массив) ссылка. Вы затем печатаете каждую строку, только если ключ хеша не был замечен прежде.

2
27.01.2020, 20:13
  • 1
    , Который сказал бы это ab,c,1,d и a,bc,2,d то же. Вам нужно join(",". Также можно оптимизировать путем перемещения $k{$a}++ в unless() { } блок. И затем, который был бы эквивалентен моему awk решение ;-). –  Stéphane Chazelas 17.09.2013, 20:10
  • 2
    я не думаю, что он определил бы ab,c,1,d и a,bc,2,d как идентичное - сравнение сделано на восстановленной строке (с запятыми в правильных местах). –  peterph 17.09.2013, 20:25
  • 3
    @peterph да, но это вызвано тем, что я уже исправил ошибку, которую Stephane определил и добавил join(",". –  terdon♦ 17.09.2013, 20:26
  • 4
    Это просто, что Вам не нужно $k{$a}++ если $a уже находится в %k. Вы могли сделать его короче с: perl -F, -ane'print if!$k{join",",@F[0,1,3..-1]}++' –  Stéphane Chazelas 17.09.2013, 22:25
  • 5
    Stephane, Ваше последнее предложение не обеспечивает ожидаемый вывод, жемчуг terdon в отредактированном ответе делает. –  bbaassssiiee 18.09.2013, 09:49

Теги

Похожие вопросы