Пример выполнения работы

Здесь мы рассматриваем примеры выполнения нескольких вариантов каждого задания.

Пример 1.1
Пример 1.2
Пример 1.3
Пример 2-3.1
Пример 2-3.2
Пример 2-3.3
Пример 2-3.4


Пример 1-1

Каждое второе слово каждой строки вывести в отдельную следующую строку. Если в строке только одно слово, ничего не делать.

Решение оказывается простейшим. В качестве символа-разделителя в тексте используется пробел, следовательно, при вызове awk определять разделитель явным образом не требуется. Слова составляют поля. Никаких специальных действий в начале или в конце обработки предпринимать не нужно. При обработке каждой строки следует сначала вывести полный текст строки ($0), а затем проверить длину второго поля строки ($2). Если длина этого поля - 0, то второе слово в строке отсутствует, и ничего предпринимать не нужно. Если длина отлична от 0, второе поле выводится в следующую строку.

Полный текст программы awk и протокол ее выполнения выглядит так:

bash2-2.05$ awk '
  { \
    /* вывод всей строки */
    print $0; \
    /* проверка 2-го слова и вывод его, если оно есть */ 
    if (length($2)>0) print $2; \
  }' Hum-Dum.txt
Humpty-Dumpty
Set on the wall.
on
Humpty-Dumpty
Had a greate fall.
a
And all the king's horses,
all
And all the king's man.
all
Can not Humpty,
not
Can not Dumpty,
not
Humpty-Dumpty,
Dumpty-Humpty,
Set on this wall
on
Again.
bash2-2.05$


Пример 1-2

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

Решение этой задачи сложнее, но не намного. Мы можем выводить строку только после того, как прочитаем следующую строку. Поэтому вводим переменную buf, которая играет роль буфера для запоминания предыдущей строки. При обработке первой строки (номер строки можно определить по системной переменной NR) ее полное содержимое только запоминается в буфере. При обработке любой следующей строки на печать выводится первый символ прочитанной строки и текст строки, запомненной в буфере (предыдущей строки) без первого символа. После окончания чтения файла в буфере остается текст последней строки, который должен быть также выведен. Для выделения первого символа строки и остатка строки без первого символа используется функция substr().

Полный текст этой программы awk и протокол ее выполнения выглядит так:

bash2-2.05$ awk '
  /* после обработки последней строки выводится последний буфер */ 
  END { printf("%s\n",buf); }
  { \
    /* при обработке первой строки это действие не выполняется */ 
    if (NR>1) { \
       /* выводится 1-й символ текущей строки          */
       /* и содержимое буфера, начиная со 2-го символа */
       printf("%c%s\n",substr($0,1,1),substr(buf,2)); \
      }  \
    /* текущая строка запоминается в буфере */
    buf=$0; \
  }' Hum-Dum.txt
Sumpty-Dumpty
Het on the wall.
Humpty-Dumpty
Aad a greate fall.
And all the king's horses,
Cnd all the king's man.
Can not Humpty,
Han not Dumpty,
Dumpty-Dumpty,
Sumpty-Humpty,
Aet on this wall
Again.
bash2-2.05$
Script done on Thu Sep  5 08:42:09 2002


Пример 1-3

В предпоследней строке, которая заканчивается точкой, поменять местами первое слово с последним.

Решение этой задачи более сложное. Сложность состоит в том, что мы не знаем, какая строка должна быть модифицирована, пока не прочитаем весь файл. Решение состоит в том, что текущая обработка файла будет в основном заключаться в сохранении строк в буфере. Буфер должен представлять собой массив строк, который будет содержать все строки файла. Вместе с накоплением строк в буфере мы определяем, является ли последний символ строки точкой, и запоминаем номера двух последних строк с точкой. После окончания чтения файла буфер содержит полный текст файла, и мы знаем номера последней и предпоследней строк с точкой.

В заключительной обработке (по шаблону END) мы перебираем строки, сохраненные в буфере. Если номер очередной строки не совпадает с номером предпоследней строки с точкой, печатаем эту строку без изменений. Если же это та самая строка, то при печати она модифицируется. Мы используем функцию awk split(), которая разбивает строку на поля, разделенные заданным символом. Части строки помещаются в заданный массив, а функция возвращает число полей, которое она обнаружила в строке. В нашем случае разделителем является пробел, а полями - слова. На печать выводится сначала последний элемент массива - результата функции split(), затем все элементы со второго по предпоследний, и наконец - первый элемент. Таким образом, в печатаемой строке первое и последнее слова меняются местами.

Полный текст программы awk и протокол ее выполнения выглядит так:

bash2-2.05$ awk '
  /* nlines - счетчик строк в файле,                           */
  /* point1 и point2 - номера строк, заканчивающихся точкой, - */
  /* последней и предпоследней соответственно                  */
  BEGIN { nlines=0; point1=0; point2=0; }
  /* основная обработка - после окончания чтения файла         */
  END { \
      /* перебираются все строки, сохраненные в буфере */
      for (i=1; i<=nlines; i++) {  \
        /* проверка - совпадает ли номер строки с обнаруженным номером */ 
        if (i==point2) {            \
          /* если совпадает - строка разбивается на слова, слова  */
          /* помещаются в массив bb; nw - число выделенных слов   */
          nw= split(buf[i],bb," "); \
          /* печатается последнее слово */
          printf("%s ",bb[nw]);     \
          /* печатаются слова от второго до предпоследнего */
          for (j=2; j<=nw; j++) printf("%s ",bb[j]); \
          /* печатается первое слово */
          printf("%s\n",bb[1]);     \
          }  \
        else  \
          /* если номер не совпадает, строка печатается как есть */
          print buf[i];     \
        }  \
      }   \
  /* обработка каждой прочитанной строки */
  { \
    /* прочитанные строки накапливаются в буфере */
    buf[++nlines]=$0;    \
    /* выделяется последний символ строки */
    k=substr($0,length($0),1); \
    /* если это точка, модифицируются номера последней и */
    /* предпоследней строк с точкой                      */
     if (k==".") { point2=point1; point1=NR; } \
  }' Hum-Dum.txt
Humpty-Dumpty
Set on the wall.
Humpty-Dumpty
Had a greate fall.
And all the king's horses,
man. all the king's man. And
And all the king's man.
Can not Humpty,
Can not Dumpty,
Humpty-Dumpty,
Dumpty-Humpty,
Set on this wall
Again.
bash2-2.05$
Script done on Thu Sep  5 08:44:36 2002


Пример 2-3.1

В файле query3 определить товар с наибольшей разностью минимальной и максимальной цены

Решение чрезвычайно простое. Это тривиальный алгоритм поиска максимума, цикл перебора строк организует для нас awk. Максимальная и минимальная цены составляют 3-е и 4-е поля строки соответственно. Для идентификации товара следует запомнить также и его название - поле 2. Разделителем полей в файле query3 является символ "!", так что awk должна вызываться с опцией -F, определяющей разделитель.

Полный текст программы awk и протокол ее выполнения выглядит так:

bash2-2.05$ awk -F ! '
   /* после окончания обработки печатаются запомненные данные */
   END { printf("%s: %f-%f=%f\n",pp,pmax,pmin,pmax-pmin) }
   /* при обработке каждой строки */
   { \
     /* если это первая строка, запоминается минимальная и         */
     /* максимальная цена и разность между ними, а также имя       */
     /* если строка не первая, но разность цен в ней превышает     */
     /* запомненную ранее, цены, разность, и имя тоже запоминаются */ 
        if ((NR==1)||($3-$4>pmax-pmin)) \
          { pp=$2; pmin=$4; pmax=$3 } \
   }' ../metod/query3
DUNK BASKETBALL PROFESSIONAL: 58.300000-40.800000=17.500000
bash2-2.05$


Пример 2-3.2

В файле query2 определить всех покупателей, у которых кредит выше среднего

Решение этой задачи требует перебрать все строки файла дважды - сначала для вычисления средней суммы кредита, а затем для определения покупателей, у которых кредит выше среднего. Поэтому при переборе строк файла awk в буфере сохраняются необходимые данные (имя покупателя и кредит) всех строк и выполняется накопление суммы кредита по всем строкам. Роль буфера играют два массива - один для имен покупателей, а другой - для их кредитов.

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

Полный текст программы awk и протокол ее выполнения выглядит так:

bash2-2.05$ awk -F : '
   /* начальные установки: число строк -0, сумма кредита - 0 */
   BEGIN { nn=0; cc=0 }
   /* заключительные действия */
   END {
       /* усреднение */
       cc/=nn;  \
       /* перебор сохраненных данных */
       /* если кредит превышает средний - печать */
       for (i=0; i<nn; i++)  \
         if (crd[i]>cc) printf("%s - %d\n",cust[i], crd[i]) \
       }  \
   /* обработка каждой строки: запоминание имени и кредита, */
   /* накопление суммы кредита, подсчет общего числа строк  */
   { cust[nn]=$2; crd[nn]=$8; cc+=$8; nn++ }
   ' ../metod/query2
TKB SPORT SHOP             - 10000
VOLLYRITE                  - 7000
EVERY MOUNTAIN             - 10000
WOMENS SPORTS              - 10000
NORTH WOODS HEALTH CENTER  - 8000
STADIUM SPORTS             - 10000
REBOUND SPORTS             - 10000
THE POWER FORWARD          - 12000
FAST BREAK                 - 7000
AT BAT                     - 8000
AL'S PRO SHOP              - 8000
BOB'S FAMILY SPORTS        - 8000
WHEELS AND DEALS           - 10000
BOB'S SWIM, CYCLE, AND RUN - 7000
bash2-2.05$


Пример 2-3.3

В файле query2 определить покупателя, который имеет максимальную цифру номера дома.

Решение довольно простое, сам алгоритм поиска максимума не представляет интереса, обратим внимание на работу с номером дома. Анализ файла query2 показывает, что адрес является третьим полем в файле, а номер дома (если он присутствует) - всегда первое слово в адресе. Однако не во всех адресах указан номер дома, адреса без этой составляющей можно просто исключить из обработки. Это можно сделать при помощи шаблона. Номер дома выделяется из адреса при помрщи функции split(), разделителем слов в адресе является пробел.

Полный текст программы awk и протокол ее выполнения выглядит так:

bash2-2.05$ awk -F : '
   /* начальное значение максимального номера -0 */
   BEGIN { nn=0 }
   /* в конце печатается найденные имя и адрес */
   END { printf("%s : %s\n",cc,aa) }
   /* обработка строк; шаблон задает обработку только тех строк, */
   /* в которых после 2-го символа : стоит одна или более цифр,  */ 
   /* а за ними - пробел                                         */
   /.*:.*:[0-9]* / { \
     /* выделение номера дома */
     split($3,a," ");  \
     /* обнаружение и запоминание максимума */
     if (a[1]>nn) { cc=$2; aa=$3; nn=a[1] } \
   }' ../metod/query2
VOLLYRITE                  : 9722 HAMILTON
bash2-2.05$


Пример 2-3.4

В файле query3 определить сумму продаж для каждого года.

Решение опять-таки требует некоторого накопления данных. Мы заранее не знаем даже, в какие годы осуществлялись продажи. Поэтому нам придется ввести два массива с синхронной индексацией: в одном мы будем фиксировать год, а в другом - число продаж в этом году. При переборе строк файла следует в каждой строке выделять год продажи и проверять, имеется ли такой год в нашем массиве годов. Если такого года нет, мы добавляем новый элемент в массив годов и устанавливаем соответствующий ему новый элемент в массиве счетчиков продаж в 1. Если такой год уже есть, мы увеличиваем соответствующий ему новый элемент в массиве счетчиков продаж на 1.

Полный текст программы awk и протокол ее выполнения выглядит так:

bash2-2.05$ awk -F ! '
   /* количестов годов -0 */
   BEGIN { nn=0 }
   /* по завершении - распечатка годов и их счетчиков */
   END { for (i=0; i<nn; i++)
         printf("%s - %s\n",year[i],cnt[i]) }
   /* обработка каждой строки */
   { \
   /* выделение года */
   y=substr($5,8,2); \
   /* перебор уже имеющихся годов; если год в текущей строке */
   /* совпадает с одним из уже имеющихся - увеличение счетчика */ 
   for (i=0; i<nn; i++) \
     if (year[i]==y) { cnt[i]++; break } \
   /* если год не совпали ни с одним из имеющихся, добавляется */
   /* новый год со счетчиком 1                                 */
   if (i==nn) { year[i]=y; cnt[i]=1; nn++ } \
   }' ../metod/query3
89 - 10
90 - 21
bash2-2.05$


 

© life-prog.ru