Замена номеров в одном диапазоне - PullRequest
2 голосов
/ 17 июня 2019

У меня есть файл с разделителями табуляции1, где первый столбец выглядит как

1
1
6
6
6
1A
1A
1B
2
2
2
2
3
4
4A
Z
Z

Я хочу заменить так, чтобы 1 = 1, 1A = 2, 1B = 3, 2 = 4, 3 = 5, 4 = 6, 4A = 7, 6 = 8, Z = 9 Выход должен быть тогда

1
1
8
8
8
2
2
3
4
4
4
4
5
6
7
9
9

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

sed -e 's/a/b/g ; s/b/d/g' file

но мне нужно сделать 60 замен.

Есть ли способ, которым я могу сделать это в цикле или какой-то другой альтернативе вместо написания 60 замен

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

Ответы [ 5 ]

3 голосов
/ 17 июня 2019

Создайте файл сопоставления со строками поиска и замены как:

cat mapping
1   1
1A  2
1B  3
2   4
3   5
4   6
4A  7
6   8
Z   9

Затем просто используйте это awk, чтобы получить все замены в одной команде:

awk 'BEGIN{FS=OFS="\t"} NR == FNR{key[$1]=$2; next} $1 in key{$1=key[$1]} 1' mapping file

1
1
8
8
8
2
2
3
4
4
4
4
5
6
7
9
9
1 голос
/ 18 июня 2019

Поскольку вы просто хотите использовать последовательные числа, начинающиеся с 1, в качестве замены, все, что вам нужно:

awk '
BEGIN {
    split("1 1A 1B 2 3 4 4A 6 Z",tmp)
    for (i in tmp) {
        map[tmp[i]] = i
    }
    FS = OFS = "\t"
}
$1 in map { $1 = map[$1] }
1' file
1
1
8
8
8
2
2
3
4
4
4
4
5
6
7
9
9
1
1 голос
/ 18 июня 2019

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

sed -E 's/$/\n:1=1:1A=2:1B=3:2=4:3=5:4=6:4A=7:6=8:Z=9/;s/^(\S+)(.*)\n.*:\1=([^:]*).*/\3\2/;P;d' file

Добавьте таблицу поиска к каждой строке и используйте сопоставление с образцом и обратные ссылки для перевода первого столбца в требуемую строку.

N.B. Строки, которые не соответствуют поиску, не будут изменены.

1 голос
/ 17 июня 2019

для префикса с одной цифрой, это будет работать без ручного сопоставления

$ awk 'NR==FNR {a[$1]; next} 
       FNR==1  {asorti(a,b); for(k in b) c[b[k]]=k} 
               {print c[$1]}' file{,}

1
1
8
8
8
2
2
3
4
4
4
4
5
6
7
9
9

обратите внимание, что 6 сопоставлено с 8, а не 4, как в примере вывода.

1 голос
/ 17 июня 2019

Не могли бы вы попробовать следующее (добавьте дополнительный FS=OFS="\t" в BEGIN раздел, если у вас есть Input_file с разделением табуляции и вам тоже нужен вывод в форме TAB).

awk '
BEGIN{
  key="1,1A,1B,2,3,4,4A,6,Z"
  value="1,2,3,4,5,6,7,8,9"
  split(key,array1,",")
  num=split(value,array2,",")
  for(i=1;i<=num;i++){
    pair[array1[i]]=array2[i]
  }
}
{
  for(i=1;i<=NF;i++){
    if($i in pair){
      $i=pair[$i]
    }
  }
}
1
'   Input_file
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...