2016-09-15 4 views
1

У меня есть большой (2 ГБ) текстовый файл с разделителями-запятыми, содержащий некоторые данные от датчиков. Иногда датчики выключены и данных нет. Я хочу удалить строки, если в каждой строке больше заданного числа No Data или Off или any non-numeric значений; исключая заголовок. Меня интересует только подсчет с третьей колонки. Например: мои данные выглядят как:Удалите строку, если она содержит более определенного числа числовых значений

Tag, Description,2015/01/01,2015/01/01 00:01:00,2015/01/01 00:02:00, 2015/01/01 00:02:00 
1827XYZR/KB.SAT,Data from Process Value,2.1,Off,2.7 
1871XYZR/KB.RAT,Data from process value,Off,No Data, No Data 
1962XYMK/KB.GAT,Data from Process Value,No Data,5,3 
1867XYST/KB.FAT,Data from process value,1.05,5.87,7.80 
1871XKZR/KB.VAT,Data from process value,No Data,Off,2 

Здесь первая строка - это заголовок, и я хочу сохранить его как есть. Но я хочу удалить те строки, которые имеют 2 или более 2 No Data или Off или любые поля non numeric в любых столбцах/полях из третьего столбца и далее. Другими словами, строки из 4 или текстовых полей из пяти. В примере выше 3-я и 6-я строки содержат 2 или более 2 No Data или Off полей, и я хочу их удалить. Поэтому, мой любимый результат будет

Tag, Description,2015/01/01,2015/01/01 00:01:00,2015/01/01 00:02:00, 2015/01/01 00:02:00 
1827XYZR/KB.SAT,Data from Process Value,2.1,Off,2.7 
1962XYMK/KB.GAT,Data from Process Value,No Data,5,3 
1867XYST/KB.FAT,Data from process value,1.05,5.87,7.80 

я могу сделать это для конкретного случая с петлей, как:

awk -F, '{ non_numeric=0; 
    for(i=1;i<=NF;i++){ 
    if($i ~ //) non_numeric++ 
    } 
    if(non_numeric<2) print $0 
}' testfile.txt 

Здесь я рассматриваю только No Data и Off. Как я могу подсчитать все нечисловые строки. Если я изменил оператор if на

if($i ~ /[^0-9]/) non_numeric++ 

он не работает и не дает выхода. Кроме того, поскольку я использую цикл, я считаю, что он будет медленным. Мы можем как-то ускорить это. Любое решение командной строки - это хорошо.

+1

Используйте цикл 'for()' для подсчета числа числовых полей. Когда цикл будет завершен, распечатайте линию, если она не менее 4. – Barmar

+3

В основном, я только что повторил ваши требования. Это должно быть просто, чтобы превратить его в код 'awk'. Пожалуйста, покажите, что вы попробовали, чтобы мы могли помочь вам исправить это. Мы не собираемся делать вашу работу за вас. – Barmar

+1

Третья строка в данных примера содержит следующее: 'Нет данных. Нет данных'. Это опечатка? был '.', который должен быть', '? – redneb

ответ

1

Вы могли бы сделать это с grep:

grep -vP '((?<=,|^)(No Data|Off)(?=,|$).*){2,}' input 

Tag, Description,2015/01/01,2015/01/01 00:01:00,2015/01/01 00:02:00, 2015/01/01 00:02:00 
1827XYZR/KB.SAT,Data from Process Value,2.1,Off,2.7 
1962XYMK/KB.GAT,Data from Process Value,No Data,5,3 
1867XYST/KB.FAT,Data from process value,1.05,5.87,7.80 

Пояснение: (No Data|Off) матчи с либо No Data или Off. Мы окружаем его (?<=,|^) и (?=,|$); они представляют собой нулевую ширину lookbehind и lookahead, которые соответствуют , или началу (или концу) строки. Это гарантирует, что мы сопоставим только с целым полем. Поскольку мы хотим многократно сопоставлять поле, мы помещаем все внутри квантифицированного (...){2,}, а также добавляем .* для учета материала между полями.

0

ленивого способа: печатать тогда и только тогда полей 3-5 содержат по меньшей мере один номер символ:

awk -F, '$3$4$5 ~ "[0-9]"' data.csv 

ленивее способ (работает для выборочных данных): печать тогда и только тогда строка содержит запятую, за которым следует номер символ:

grep ',[0-9]' data.csv 
2
awk -F, ' 
    { nonnum = 0; 
     for (i = 3; i <= NF; i++) { 
      if ($i ~ /[^.0-9]/) { 
       nonnum++; 
       if(nonnum >= 2) { next; } 
      } 
     } 
    } 1' infile > outfile 

1 на концах выводит строку, если цикл не выполняется next, чтобы пропустить оставшиеся шаблоны для текущей строки.

+0

Спасибо! Я думаю, что это должно быть 'i <= NF', это провалится для случая, когда последние три столбца являются числовыми, нечисловыми, нечисловыми. Я буду ждать когда-нибудь, если я получу более быстрое решение, иначе я приму этот ответ. – discipulus

+1

Я думаю, что ['' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' избыточно) (https://www.gnu.org/software/gawk/manual/html_node/Next-Statement.html) – anishsane

1

со статическими строками:

$ awk '(a=$0) && gsub(/No Data|Off/,"",a)<2' file 

Т.е.. скопировать текущую запись $0 переменной темп a, подсчитывает количество occurrances из Off и No Data использования gsub и print если количество меньше 2. Выход:

Tag, Description,2015/01/01,2015/01/01 00:01:00,2015/01/01 00:02:00, 2015/01/01 00:02:00 
1827XYZR/KB.SAT,Data from Process Value,2.1,Off,2.7 
1962XYMK/KB.GAT,Data from Process Value,No Data,5,3 
1867XYST/KB.FAT,Data from process value,1.05,5.87,7.80 

Если вы хотите, чтобы соответствовать все нецифровой строке , использовать:

awk 'NR==1 || (a=$0) && gsub(/,[^\.,0-9]+/,"",a)<3' file 

Он выдает первую запись (NR==1) и записи с менее чем за три нечисловых значений (третий из них является ,Data from process value).

+0

Спасибо, но есть способ, регулярное выражение для рассмотрения других строк, я хочу считать все, что не является числовым, используя /[^0-9.]/ в gsub does't work – discipulus

0

Это может работать для вас (GNU СЭД):

sed -r '/(.*No Data|.*Off){2}/d' file 

Использование Чередование для удаления линий с 2 ​​или более из указанных строк.

+0

Есть ли способ, regex, чтобы рассмотреть другие строки, а также, я хочу считать все, что не является числовым – discipulus

1

С GNU AWK вы можете использовать этот ханжа:

awk 'NF<2' FPAT='No Data' file 

FPAT определяет шаблон, который описывает то, что это поле в строке текста. Это расширение GNU. Установка его на статическую строку No Data позволяет нам просто проверить количество полей с помощью NF<2.

1
$ perl -F, -ane 'print if $. == 1 || (grep {!/\d/} @F[2..$#F]) < 2' ip.txt 
Tag, Description,2015/01/01,2015/01/01 00:01:00,2015/01/01 00:02:00, 2015/01/01 00:02:00 
1827XYZR/KB.SAT,Data from Process Value,2.1,Off,2.7 
1962XYMK/KB.GAT,Data from Process Value,No Data,5,3 
1867XYST/KB.FAT,Data from process value,1.05,5.87,7.80 
  • -F, разделение входной линии на ,
  • $. == 1, если номер строки 1, т.е. печать заголовка
  • (grep {!/\d/} @F[2..$#F]) < 2 печать, если количество нечисловых полей в колонках 3 до конца меньше, чем два , Условие просто проверяет, нет ли цифры

Столбы для проверки и количества проверок можно легко изменить в зависимости от требований. Например: @F[3..$#F] проверяет 4-й столбец, < 3 проверяет количество нечисловых полей менее трех