Заполните пустые столбцы в текстовом файле 0

У меня есть набор данных, который я вырезал и вставлял из электронной таблицы Google в свой текстовый редактор (Sublime Text 2), и этот набор данных не совсем соответствует моим потребностям в обработке.

В той форме, в которой они исходят из электронной таблицы, данные начинаются с одной строки строк, по одной для каждого столбца, а затем ряда строк с данными; в строках данных каждый столбец либо имеет значение 1, либо пуст. Я не знаю, разделены ли данные табуляцией, когда они поступают из электронной таблицы, но после вставки в текстовый файл это не так. Если последний 1в строке не находится в последнем столбце, строка дополняется пробелами до но не включая последний столбец.

Я пытался что-то сделать с awk, но не мог понять, как справиться с тем фактом, что пробел является и разделителем, и значением столбца. Затем я попробовал несколько команд с sed, в том числе замену повторяющихся пробелов нулями и переход к другому sed, который заменял 10 на 1 0, но иногда у меня иногда вставлялись лишние нули, и я не знаю, где в соответствующих строках это произошло.

Это пример данных (в реальном файле 13 столбцов). Я добавил $ в качестве символа после последнего символа в строке, чтобы вы могли видеть, насколько далеко заполняются строки.

"1" "2" "3" "4"                           "1" "2" "3" "4"
  1 1 $                                   0 1 1 0
1     1 $                                 1 0 0 1
  1   $                                   0 1 0 0
1 1   1 $                                 1 1 0 1

Я хотел бы получить что-то вроде права (и тогда мне все равно, где заканчивается строка), чтобы я мог обработать его с помощью awk.

И кстати, я видел это вопрос , который не решает мою проблему, поскольку решение там основано на том факте, что файл разделен табуляцией, без каких-либо значений в «пустых» ячейках. Повторюсь, мой файл разделен пробелами с пробелами в пустых ячейках.


person Tomas Aschan    schedule 20.04.2013    source источник


Ответы (2)


Моя первая попытка не удалась. Итак, моя 2-я 3-я 4-я попытка основана на измененном вводе с автоматическим определением количества столбцов:

awk 'NR==1{for(;N<NF;++N)sp=" 0"sp}NR>1{$0=" "$0;sub(" +$","");gsub("  "," 0");$0=substr($0sp,2,2*N-1)}1'<<EOT
"1" "2" "3" "4"
  1 1 
1     1 
  1   
1 1   1 
EOT

Первые пробелы четные, между ними нечетные, поэтому я добавил пробел в начале, чтобы использовать один и тот же gsub для обоих случаев. Неясно, сколько пробелов присутствует в конце, поэтому скрипт их просто пережевывает. Он содержит количество 0 раз поля. Substr начинается с 2, чтобы сократить добавленный начальный пробел, и длится до (number of fields)*2-1 символов, чтобы сократить конечный пробел.

Выход:

"1" "2" "3" "4"
0 1 1 0
1 0 0 1
0 1 0 0
1 1 0 1
person TrueY    schedule 20.04.2013
comment
Это хорошее решение, но я бы предпочел такое, которое не зависит от количества полей, чтобы я мог повторно использовать его для других файлов данных с той же проблемой. Добавление переменной (например, с -v N=7) — это нормально, если это необходимо, но если бы сам скрипт был NF-агностическим, было бы еще лучше... - person Tomas Aschan; 22.04.2013
comment
@Thomas Lycken: Хорошо, код изменен. Количество элементов можно определить по первому ряду. - person TrueY; 22.04.2013

Попытка объяснить, почему проблема сложна, повышает ваши шансы ее решить. Просто потому, что я подумал об объяснении здесь, я также придумал решение =)

Решение работает с sed и в основном состоит из трех шагов:

  1. Замените все пустые столбцы first на 0:

    cat datafile.txt | sed 's/^ /0 /g'
    
  2. Замените все пустые столбцы last на 0:

    cat datafile.txt | sed 's/^ /0 /g' | sed 's/  $/  0/g'
    

    Здесь мне пришлось немного поэкспериментировать с количеством пробелов в регулярном выражении, чтобы правильно выровнять все новые нули.

  3. Замените все пустые столбцы inner на 0:

    cat datafile.txt | sed 's/^ /0 /g' | sed 's/  $/  0/g' | sed 's/  / 0/g'
    

    Здесь я также экспериментировал с размещением 0 первым или последним в регулярном выражении замены, чтобы все было правильно.

И, конечно же, после того, как это будет сделано, я перенаправляю вывод в файл, помечая > datafile-clean.txt в конце.

Вероятно, есть более элегантный способ сделать это, поэтому, если он у вас есть, опубликуйте его, хотя лично мне это решение больше не нужно.

Обновление. Как показано в комментариях, это решение можно значительно улучшить. Я оставлю исходное решение здесь, так как я думаю, что оно более понятно, что оно делает и в каком порядке, но, вероятно, следует использовать его вместо этого.

Начнем с того, что нам не нужно так много труб; вместо этого мы используем флаг -e для sed:

sed -e 's/^  /0 /' -e 's/  $/ 0/' -e 's/  / 0/g' datafile.txt

Это работает как есть, учитывая, что первая строка с заголовками столбцов не содержит двойных пробелов. Если это так, можно просто прочитать файл с помощью tail -n +2 datafile и подключиться к приведенной выше команде sed.

person Tomas Aschan    schedule 20.04.2013
comment
Пожалуйста, пожалуйста, не используйте cat file|sed ...! Вы просто тратите ресурсы зря. Вместо этого используйте sed ...<file! Или более удобная форма sed ... file. Насколько я знаю, sed может обрабатывать несколько определений правил. Так что используйте только один sed! - person TrueY; 21.04.2013
comment
Действительно ли нужен g для таких шаблонов, как /^.../ и /...$/? Их можно сопоставить только один раз. - person TrueY; 21.04.2013
comment
К сожалению, нет случая, соответствующего шаблону / $/. Последний символ всегда одиночный пробел. - person TrueY; 22.04.2013
comment
@TrueY: На самом деле, есть случаи с более чем одним пробелом перед концом строки - к сожалению, из-за плохого выбора примеров строк это не отразилось в представленных мной данных. Я обновил, чтобы отразить это. - person Tomas Aschan; 22.04.2013
comment
До сих пор не ясно, сколько завершающих пробелов добавляется к каждой строке. Во 2-й строке ввода есть только один пробел в конце, но нужно добавить ноль. Но в 3-й строке также есть один завершающий пробел, и если закончить с одним. Так что мое решение не учитывает количество завершающих пробелов. - person TrueY; 22.04.2013