Как я могу заменить символы после определенного соответствия + смещение?

Вопрос или проблема

У меня есть файл, содержащий значения, которые нужно скрыть (заменить на XX), но они не всегда находятся на одном и том же месте в строке, и я не знаю их содержимого. Однако я знаю их расположение относительно конкретного совпадения.

Например, я хочу, чтобы третье и четвертое числа после “00 00” были заменены на XX

Оригинал:

AA BB CC 00 00 01 02 03 04 05 06 07
AA BB CC DD EE FF 00 00 08 09 10 11 12 13 14

Желаемый вывод:

AA BB CC 00 00 01 02 XX XX 05 06 07
AA BB CC DD EE FF 00 00 08 09 XX XX 12 13 14

Я пробовал использовать awk, но мне удалось только установить позицию относительно начала строки. Есть ли способ индексации $2 и $3 относительно конкретного совпадения, например?

Правка: в строке может быть только одно совпадение 00 00, она не может содержать 00 00 00, не нужно беспокоиться о ведущем или завершающем совпадении.

Моя (стыдная) попытка на данный момент была следующей:

cat file | awk -F'00 00' '{print $2}' | awk '{gsub ($3,"XX",$0);gsub ($4,"XX",$0)}1'

Помимо множества awk, я также теряю начало строк, так как все, что перед совпадением, отбрасывается моим первым awk

С использованием sed или perl это проще, чем с awk, если у вас нет awk, который поддерживает расширение gawk‘s gensub():

sed 's/\(00 00 .. .. \).. ../\1XX XX/' < file
perl -pe 's/00 00 .. .. \K.. ../XX XX/' < file
gawk '{print gensub(/(00 00 .. .. ).. ../, "\\1XX XX", 1)}' < file

С POSIX awk можно сделать так:

awk '
  match($0, /00 00 .. .. .. ../) {
    $0 = substr($0, 1, RSTART+11) "XX XX" substr($0, RSTART+RLENGTH)
  }
  {print}' < file

Вот один из подходов с использованием awk:

$ awk '
{ 
  for(i=1; i<=NF; i++){ 
    if($i=="00" && $(i+1)=="00"){
      $(i+4)=$(i+5)="XX"
    }
  }
}1' file 
AA BB CC 00 00 01 02 XX XX 05 06 07
AA BB CC DD EE FF 00 00 08 09 XX XX 12 13 14

Идея заключается в том, чтобы пройти по всем полям (for(i=1; i<=NF; i++); NF – это количество полей) и искать случаи, когда текущее поле ($i) и следующее ($(i+1)) установлены в строку 00. Затем мы меняем 3-е и 4-е поля на XX ($(i+4)=$(i+5)="XX"; используя +4 и +5, поскольку я считаю от первого 00, а не от второго). Наконец, мы выводим всё. Действие по умолчанию для awk, когда выражение оценивается как истинное, – это вывести строку, поэтому простое 1, которое всегда истинно, часто используется как сокращение для print.

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

$ cat file 
AA,BB,CC,00,00,01,02,03,04,05,06,07
AA,BB,CC,DD,EE,FF,00,00,08,09,10,11,12,13,14

$ awk -F',' -v OFS=',' '
{ 
  for(i=1; i<=NF; i++){ 
    if($i=="00" && $(i+1)=="00"){
      $(i+4)=$(i+5)="XX"
    }
  }
}1' file 
AA,BB,CC,00,00,01,02,XX,XX,05,06,07
AA,BB,CC,DD,EE,FF,00,00,08,09,XX,XX,12,13,14

Вы также можете просто рассматривать это как простую замену и сделать что-то вроде:

$ sed -E 's/( 00 00 .. ..) .. ../\1 XX XX/' file 
AA BB CC 00 00 01 02 XX XX 05 06 07
AA BB CC DD EE FF 00 00 08 09 XX XX 12 13 14

Или

$ perl -pe 's/( 00 00 .. ..) .. ../$1 XX XX/' file 
AA BB CC 00 00 01 02 XX XX 05 06 07
AA BB CC DD EE FF 00 00 08 09 XX XX 12 13 14

Используя awk:

$ awk '
      match($0, /00 00 [0-9]+ [0-9]+/)
       {
          printf substr($0,1,RSTART+RLENGTH)  
          $0=substr($0,RSTART+RLENGTH+1);
          sub(/^[0-9]+ [0-9]+/, "XX XX")
   }1' file

При условии, что только числа повторяются после 00 00.

Ответ или решение

Чтобы заменить символы после конкретного совпадения с учетом сдвига, как в вашем вопросе, можно использовать несколько различных инструментов, таких как awk, sed или perl. Давайте проанализируем каждое из этих решений и выберем наиболее подходящее.

Проблема

Вы хотите заменить третий и четвертый числа после строки "00 00" на "XX", и делаете это в текстовом файле с множеством строк. Важно, чтобы значение "00 00" встречалось в каждой строке только один раз, и нам нужно сохранить все остальные значения и структуру строки.

Решения

1. Использование awk

awk — мощный инструмент для обработки текстовых данных. Вот один из возможных способов:

awk '{
  for(i=1; i<=NF; i++){
    if($i=="00" && $(i+1)=="00"){
      $(i+4)=$(i+5)="XX"
    }
  }
} 1' ваш_файл.txt

Объяснение:

  • Мы проходим по всем полям (NF — количество полей в строке).
  • Если текущее поле равно "00", а следующее тоже "00", мы заменяем третье и четвертое числа после "00 00" на "XX".
  • 1 в конце является сокращением для команды print, что позволяет вывести измененную строку.

2. Использование sed

sed — идеальный инструмент для простых подстановок на основе регулярных выражений. Вот пример команды:

sed -E 's/(00 00 [0-9]+ [0-9]+) [0-9]+ [0-9]+/\1 XX XX/' ваш_файл.txt

Объяснение:

  • Здесь мы используем -E для включения расширенных регулярных выражений.
  • Мы ищем последовательность "00 00" с двумя числами после, а затем заменяем следующие два числа на "XX".

3. Использование perl

perl также предоставляет возможность обрабатывать текстовые потоковые данные и может быть очень эффективным:

perl -pe 's/(00 00 [0-9]+ [0-9]+)\s+[0-9]+\s+[0-9]+/$1 XX XX/' ваш_файл.txt

Объяснение:

  • Здесь мы используем регулярное выражение для поиска "00 00" и двух последовательных чисел.
  • Затем мы заменяем два следующих числа на "XX".

Вывод

Каждый из предложенных подходов имеет свои преимущества. Если вам нужно более сложное условие обработки данных, используйте awk. Если вам нужна простая подстановка, sed или perl подойдут идеально. Учитывайте также, что использование awk может дать вам больше гибкости для дальнейшей обработки строк, тогда как sed и perl более эффективны для простых операций замены.

Заключение

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

Оцените материал
Добавить комментарий

Капча загружается...