2013-03-11 2 views
4

Я немного разбираюсь в различиях между GNU sed и BSD sed. К сожалению, у меня нет Linux-машины, доступен только Mac.BSD sed не может заменить все «, 0»,

У меня есть большой файл данных в формате csv, разделенный запятой. Даже первые две строки файла слишком велики для публикации здесь, вы можете найти первые две строки here.

Мне нужно заменить значения «0,8,9», -999, -999.0 на «NA», поскольку эти значения являются кодами для отсутствующих значений.

Я использовал следующую команду в патч в Баш строке

sed -e 's/\-999\.?\0?/NA/g' \ 
    -e 's/\-999/NA/g' \ 
    -e 's/,9,/,NA,/g' \ 
    -e 's/,8,/,NA,/g' \ 
    -e 's/,0,/,NA,/g' \ 
    firsttwolines.csv 

Результат выглядит отлично, за исключением все еще существует единого 0. Как это исправить? И как поместить его в сценарий bash? Есть ли лучший способ выполнить эту задачу?

+3

Я предполагаю, что ваш вклад содержит ', 0,0,', и ваш вывод содержит ', NA, 0,'? Если это так - это потому, что каждая замена ', 0,' может начинаться только после позиции, где предыдущая замена ', 0,' уходит. – ruakh

+0

Действительно! Как бороться с ', 0,0,' то? –

+0

Если никакое значение, отличное от 0, не может начинаться с 0, тогда просто ', 0' => ', NA' – stark

ответ

0

Я думаю, AWK будет лучшим выбором для этой задачи (протестировано с простака и nawk):

awk '{ for(i=1; i<=NF; i++) if($i == 0 || $i == 8 || $i == 9 || $i == -999) $i = "NA" } 1' FS=, OFS=, firsttwolines.csv 

для-петли проходит через каждое поле и тестирует его на равенство с перечнем NA, если верно поле заменяется NA, обратите внимание, что AWK преобразует поле в число перед тестированием. 1 в конце вызывает блок по умолчанию { print $0 }.

1

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

# csvreplace.py 

import sys 
import csv 

if __name__ == '__main__': 
    infilename = sys.argv[1] 
    outfilename = sys.argv[2] 

    with open(infilename) as infile, open(outfilename, 'w') as outfile: 
     csvreader = csv.reader(infile) 
     csvwriter = csv.writer(outfile) 
     na_list = ['0', '8', '9', '-999', '-999.0'] 
     for row in csvreader: 
      row = [col in na_list and 'NA' or col for col in row] 
      csvwriter.writerow(row) 

Вы можете использовать его в Баш скрипт, как:

python csvreplace.py data.csv out.csv 
0

С СЕПГ, попробуйте:

sed -e 's/\-999\(\.0\)*/NA/g' -e :a -e 's/,[089],/,NA,/; ta' file 
Смежные вопросы