Удаление числовых значений в определенных столбцах с сохранением знаков минус?

9

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

-1  2  3  4 -5  9
 2  3 -4  5 -6  11

И я хочу, чтобы 2-й, 4-й и 6-й полные столбцы (или каждый четный столбец) и знаки минус только от 1-го, 3-го и 5-го (или каждого нечетного столбца), поэтому я получаю это:

- 2   4 - 9
  3 - 5 - 11

И в конечном итоге в конечном итоге это:

-2  4 -9
 3 -5 -11

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

Есть ли способ сделать это с помощью awk / sed?

Это примерно так:

awk '{ for (i=2;i<=NF;i+=2) $i="" }1' FILE.txt | sed 's/[0-9,.]*//g' 
Asfound
источник
Когда вы говорите, что ваш фрейм данных продолжается бесконечно, вы имеете в виду горизонтально или вертикально? Сколько столбцов у вас на самом деле?
Тердон
Обе. Мои тестовые данные - 3 строки на 3 столбца, но фактические данные имеют различные числа, я бы сказал, до 40 строк и 40 столбцов.
Asfound

Ответы:

2

Вот один из способов:

$ awk '{for(i=1;i<=NF;i+=2){if($i<0){$i="-"}else{$i="";} }};1' file |
     sed 's/- */-/g; s/  */ /g'
-2 4 -9
 3 -5 -11

awkСкрипт переходит все нечетные столбцы и устанавливает их значение , -если они являются отрицательными , и если не опорожнить. Затем sedудаляет все пробелы после a, -а затем заменяет несколько последовательных пробелов на один. Обратите внимание, что это означает, что выравнивание будет нарушено, поскольку в некоторых полях будет два или более символов, а в других - один. Это не будет проблемой, если вы работаете с полями, они просто не выглядят красиво.

Тердон
источник
4

sedОбразом:

sed -E '
    s/^(([ \t]*-?[ \t]*[0-9.]+[ \t]+[0-9.]+)*)[ \t]+-?[ \t]*[0-9.]+$/\1/;
    s/[0-9.]+[ \t]+([0-9.]+)/\1/g'

Вывод:

-2  4 -9
 3 -5 -11

Первое выражение убивает завершающий столбец, если существует нечетное количество столбцов. Это делается путем поиска 0 или более пар <number> <number>, где первое число может быть отрицательным.

Изменить: более короткое sedрешение, вдохновленное @mikeserv:

sed -E '
    s/[0-9.]+[ \t]*([0-9.]*)/\1/g;
    s/[- \t]*$//'

То же самое с perl:

perl -lpe 's/^((\s*-?\s*[\d.]+\s*[\d.]+)*)\s+-?\s*[\d.]+$/$1/o; s/[\d.]+\s+([\d.]+)/$1/g'

Другой способ perl(вероятно, самый чистый):

perl -lpe '$a = 1; s/([\d.]+\s*)/$a++ % 2 ? "" : $1/eg; s/[-\s]*$//o'
lcd047
источник
Это отлично работает с моими фактическими данными, пока я добавляю десятичные точки в скрипт. Спасибо!
Asfound
@ Asfound Хорошо, я отредактировал свой ответ, чтобы также поддерживать десятичные точки.
lcd047
Подождите, это не удастся, если в последнем (нечетном) поле есть отрицательное значение.
Тердон
@terdon Сбой, если есть нечетное количество столбцов, да. Но есть либо ровно 6 столбцов, либо «бесконечно много», и «бесконечно много» не является нечетным числом. :)
lcd047
ОП сказал, что может быть «до 40 столбцов» :(
terdon
3

Один perl:

$ perl -anle 'BEGIN{$,=" "}
  print map{$_=$F[$_]=~/^-/?"-$F[$_+1]":" $F[$_+1]"}grep{!($_%2)}0..$#F' file
-2  4 -9
 3 -5 -11
  • -anразделить ввод на @Fмассив
  • BEGIN{$,=" "} установить разделитель поля вывода на пробел
  • grep{!($_%2)}0..$#Fполучить все четные индексы в @Fмассиве, которые являются индексами нечетных элементов
  • map{$_=$F[$_]=~/^-/?"-$F[$_+1]":" $F[$_+1]"}проверить, начинается ли нечетный элемент с -, затем добавить -следующий четный элемент, иначе добавить пробел
cuonglm
источник
3

Как ответ @ terdon, но без седа:

awk '{ for(i=1;i<=NF;i+=2){
         if ($i<0) $(i+1)*=-1;
         $i = "";
       }
       print
     }'
meuh
источник
3

pythonрешение

python -c 'from __future__ import print_function; 
import sys, math;
for line in sys.stdin:
  x = [int(y) for y in line.split()]
  print(*[int(math.copysign(b, a)) for a, b in zip(x[::2], x[1::2])], sep=" ")
' <file
Iruvar
источник
2

Простое математическое awkрешение:

$ cat <<M | awk '{for(i=2;i<=NF;i+=2){printf "%4s",($(i-1)<0?-1:1)*$i}print ""}'
-1  2  3  4 -5  9
2  3.2 -4  5 -6
M

  -2   4  -9
 3.2  -5
  • Цикл от второго ( i=2) к последнему полю ( i<=NF).
  • Умножьте предыдущее поле ( $(i-1)) на -1 или 1.
  • Хорошо отформатируйте вывод ( printf "%4s") и напечатайте завершающий перевод строки ( print "").

Единственное предостережение: если у вас нечетное количество столбцов, последнее поле вообще ничего не отобразит. Я надеюсь, что это то, что вы ожидаете. Видимо, это то, что вы ожидаете. :)

(отредактировано для работы с десятичными значениями и для выравнивания условий цикла с вопросом при сохранении 2 символов.)

ХИК
источник
1

Вы должны полностью забыть негатив - оставьте это. Вы хотите объединить два поля - слева направо. Это очень просто.

sed '   s/ *\(.*\)/\1 /
        s/\([0-9]*  *\)\{2\}/\1/g
        s/[ -]*$//
' <<\IN
-1  2  3  4 -5  9
 2  3 -4  5 -6  11
IN
-2  4 -9
3 -5 -11

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

Когда вы указываете \{числовой интервал повторения \}для \(подвыражения \), \1обратная ссылка указывается только для последнего вхождения этого выражения . Таким образом, вы можете просто сжать - или обрезать - интервал повторения, который легко. И поскольку мы сжимаем повтор за знаком - если он есть - второе вхождение этого паттерна будет следовать за любым знаком, который раньше предшествовал первому.

Описанное выше поведение определяется POSIX для всех BRE-совместимых приложений, но очень немногие sedпонимают это правильно. GNU sedделает.

Наконец, пробелы просто для того, чтобы сделать шаблон регулярным .

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

mikeserv
источник
Это будет работать только при наличии четного количества полей.
Тердон
@terdon - Нет - это работает для чего угодно.
mikeserv
Нет, попробуйте с нечетным количеством полей. Последний напечатан, и это не должно быть.
Тердон
@terdon - почему бы и не быть? Нет следующего поля для его отмены? Аскер заявляет, что они хотят удалить нечетные столбцы, за которыми следует четный столбец. За последним столбцом не следует четный столбец - он делает именно то, что должен, и удаляет как можно меньше. Предполагать, что некоторые данные должны идти, на мой взгляд, плохая практика.
mikeserv
Нет, они этого не делают: «Мне нужны значения из четных столбцов без изменений и нечетных столбцов, если есть отрицательное значение, оставьте« только »и, если есть положительное значение, откажитесь от него». Нечетные поля никогда не должны быть напечатаны, единственная информация, которую они должны сообщить, является ли они отрицательными. Твое печатает положительные нечетные поля.
Terdon