Форум программистов, компьютерный форум, киберфорум
Shell, Bash
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.60/5: Рейтинг темы: голосов - 5, средняя оценка - 4.60
2 / 2 / 0
Регистрация: 16.10.2020
Сообщений: 2
1

awk и удаление лишних строк

16.10.2020, 12:25. Просмотров 999. Ответов 4

Здравствуйте!

Столкнулся с проблемой выборки текста средствами awk в файле вида:
Код
TEXT
TEXT XYZ
XY TEXTTE
XY TEXT
XY TEXTTEXT
XY-TEXTTEXT TEXT XY
XY-TEXTTEXT TEXT XY (TEXT)
XY-TEXTTEXT TEXT XY (TEXTTEXT)
XY-TEXTTEXT TEXT XY (TEXTTE)
Хотел получить следующий вывод по самому короткому совпадению:
Код
TEXT
XY TEXTTE
XY TEXT
XY TEXTTEXT
XY-TEXTTEXT TEXT XY
Родилась следующая конструкция:
Bash
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/awk -f
$0 !~ /((\r\n|\n|\r)$)|(^(\r\n|\n|\r))|^\s*$/{
  while (NR <= 200) {
    z1=$0; y1=$1; y10=$2; y100=$3; x1=length($0); w1=NF;
    getline
    z2=$0; y2=$1; y20=$2; y200=$3; x2=length($0); w2=NF;
    #во имя отладки ты и родилась: print "W="w1","w2", X="x1","x2", Y="y1","y2", Y2="y10","y20", Z="z1","z2;
    if      (z1 ""!= z2 ""&&(y1 ""== y2 ""&& (y10 != ""|| y20 != "")) && x2 < x1) {print z2}
    else if (z1 ""!= z2 ""&&(y1 ""== y2 ""&& (y10 != ""|| y20 != "")) && x1 < x2) {print z1}
    else {printf z1"\n"z2"\n"};
    break
  }
}
Пробежавшись по форуму натолкнулся на следующую конструкцию: awk '!D[$1]++' filename , что меня очень и очень заинтересовало. Прекрасно понимаю, что оно делает, но пока не дошёл как приспособиться к этой конструкции, потому как она делает выборку по первой подстроке.

Больше готового решения жажду наводки. Банальности вроде "прочти руководства тонну" и ссылка: принимаются ;-).

Всем добра.

P.S. задачу свою в любом случае решил башем, хочется средствами awk. Заранее спасибо.
P.P.S. ЧЯДНТ?
2
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
16.10.2020, 12:25
Ответы с готовыми решениями:

Сцепка текста в ячейках, если совпадают значения в столбце А, удаление повторов имен, удаление лишних строк
Добрый день, подскажите, как решить задачу: Есть список организаций с контактами. Одна организация...

Сортировка и удаление лишних строк
Помогите с кодом сортировки. В общем в текстовую строку пишите номер магазина, все записи с этим...

Удаление лишних строк в reg-файле
Приветствую всех ! К примеру имеется дамп ветки реестра HKLM\SYSTEM\CurrentControlSet\services...

Удаление лишних строк - доделать макрос
Приветствую знатоков и прошу помочь доделать код. Есть текстовые данные, разбитые постранично. На...

4
49 / 49 / 14
Регистрация: 21.03.2011
Сообщений: 111
16.10.2020, 12:42 2
Исходя из условия, должно помочь

Bash
1
awk '(length($1) > 2 && !D[$1]++) || (length($1) <= 2 && !D[$1,$2]++)' filename
1
Эксперт NIX
1401 / 562 / 200
Регистрация: 28.06.2015
Сообщений: 1,256
Записей в блоге: 16
16.10.2020, 17:18 3
Лучший ответ Сообщение было отмечено apeshand как решение

Решение

Попробовала изменить порядок строк во входном файле и усложнить ради спортивного интереса:
cat file:
Bash
1
2
3
4
5
6
7
8
9
10
11
12
TEXT XYZ
TEXT
XY TEXT
XY TEXTTE
XY-TEXTTEXT TEXT XY
XY-TEXTTEXT TEXT XY (TEXT)
XY TEXTTEXT
XY-TEXTTEXT TEXT XY (TEXTTEXT)
XY-TEXTTEXT TEXT XY (TEXTTE)
XY-TEXTTEXT TEXT X
XY-TEXTTEXT TEXT XYZ
TEX
cat awk.sh:
Bash
1
2
3
4
5
6
#!/bin/bash
awk '
NR==FNR {A[$0]; next}
        {a=$0; NF-=1; if(!($0 in A)) D[a]}
END     {for(i in D) print i}
' file{,}
Bash
1
2
3
4
5
6
7
8
9
./awk.sh
XY TEXTTE
XY-TEXTTEXT TEXT XY
TEXT
TEX
XY-TEXTTEXT TEXT XYZ
XY TEXTTEXT
XY TEXT
XY-TEXTTEXT TEXT X
Добавила сортировку:
Bash
1
2
3
4
5
6
awk '
BEGIN   {PROCINFO["sorted_in"]="@ind_str_asc"}
NR==FNR {A[$0]; next}
        {a=$0; NF-=1; if(!($0 in A)) D[a]}
END     {for(i in D) print i}
' file{,}
Bash
1
2
3
4
5
6
7
8
9
./awk.sh
TEX
TEXT
XY TEXT
XY TEXTTE
XY TEXTTEXT
XY-TEXTTEXT TEXT X
XY-TEXTTEXT TEXT XY
XY-TEXTTEXT TEXT XYZ
2
2 / 2 / 0
Регистрация: 16.10.2020
Сообщений: 2
16.10.2020, 18:00  [ТС] 4
Спасибо за Ваш ответ, nezabudka, и ответ sonar200.

Возник ряд вопросов касательно кода с сортировкой:
BEGIN {PROCINFO["sorted_in"]="@ind_str_asc"}
- вот эта магия совершенно непонятна. Символ @ в awk встречал разве что... касательно выборок по паттерну вида @/foo/ - жёсткий поиск, насколько помню в отличии от /foo/ - нахождения в строке.
NR==FNR {A[$0]; next}
- как понимаю тут формируется одномерный массив содержащий в первом столбце всю строку $0 пока NR - номер строки, не сравняется с общим количеством строк FNR на входе. Какой-то странный аналог while без while, как мне видется.
{a=$0; NF-=1; if(!($0 in A)) D[a]}
- тут объявляется переменная a, равная всей строке $0; теперь непонятно - зачем мы отнимаем у строки единицу в значении кол-ва полей?; последняя конструкция этой строки чуточку яснее "если строка $0 не в массиве A, то" что - что это значит? Спрашиваю, потому как подобная конструкция была в моём вопросе, значащая дубль. То есть выходит, что это создаёт дубль строки?
END {for(i in D) print i}
- опять непонятно. "для каждой i в D(БОЖЕЧКИ! АБЯСНИТЕ!) печатай i"
file{,}
- что значат фигурные скобки с запятой применительно к названию?

Как говорил ранее - можете направить на чтение документации, если в доке есть примеры - спасёт время и нервы, если нет - пожалуйста объясните, хотя бы своими словами.

P.S. в итоге из 5 строчек у меня счёт на понимание меньше единицы.
0
Эксперт NIX
1401 / 562 / 200
Регистрация: 28.06.2015
Сообщений: 1,256
Записей в блоге: 16
16.10.2020, 20:14 5
apeshand, Судя по уровню ваших вопросов, рискну объяснить своими словами, думаю это будет полезней, но все равно вам стоит хотя бы по диагонали пролистать ман страничку man awk.
PROCINFO это внутренняя переменная - массив, через который можно влиять на работу процессора awk в том числе и сортировку. Попробуйте изменить значение с "@ind_str_asc" на "@ind_str_desc" и получите обратную сортировку по убывающей. Заметно невооруженным глазом, что значение состоит из трех объектов, читаю с переводом на русский по порядку @индекс_строка_поВозростанию, следующая - @индекс_строка_поУбыванию. Индекс - в данном случае имеется ввиду ключ
NR==FNR {A[$0]; next} Предполагает что процессор работает с несколькими файлами и массив из всех строк первого файла создается в переменной А. Я написала один и тот же файл в программе два раза, применяя "Расскрытие скобок", первый раз читая файл процессор создает массив, а второй производит обработку с записью в другой массив D. Расскрытие скобок или Brace Expantion хорошо наблюдать через команду echo:
Bash
1
2
echo 1{a,b,c}
1a 1b 1c
или как в нашем случае:
Bash
1
2
echo file{,}
file file
Получим как видите 2 файла. Их можно в программе так и указать безо всяких раскрытий скобок. Кстати, два файла нужны в моем случае из за того, что порядок следования строк перемешан и зачастую более короткое значение идет после длинного и необходимо к моменту обработки иметь полную базу всех вариантов.
Что касается вот этой конструкции {a=$0; NF-=1; if(!($0 in A)) D[a]}, давайте немного изменим программу и возьмем в качестве аргумента ваш первоначальный пример входного файла:
Bash
1
2
3
4
5
6
7
awk '
NF == 1 {a=$0; NF=0; if (!($0 in D)) D[a]}
NF == 2 {a=$0; NF=1; if (!($0 in D)) D[a]}
NF == 3 {a=$0; NF=2; if (!($0 in D)) D[a]}
NF == 4 {a=$0; NF=3; if (!($0 in D)) D[a]}
END     {for(i in D) print i}
' file
Смотрите что получается, я начну объяснять со второй строчки программы. В строке тело выполняется если строка состоит из двух слов (полей), переменная NF количество полей в строке. Мы присваиваем переменной a всю строку целиком, чтобы не потерять это значение, потому что следующая операция не обратима. Урезаем количество полей на единицу NF=1. Теперь у нас вся строка определенная в переменной $0 урезается на одно - последнее поле, и там ноходится только первое. Теперь проверяем есть ли совпадение в ключе массива D, если нет, добавляем в массив значение (0 по умолчанию) с ключем - первоначальной, не урезанной, полной строкой. Это дает нам возможность применить нежадный алгоритм - то есть по короткому совпадению.
Возвращаемся и видим что одна строчка в боевой программе является универсальной и заменяет множество возможных вариантов из учебной.
Как только скрипт обработает значения и создаст результирующий массив данных, можно прочитать его ключи в цикле и вывести на экран. То есть уже после того как файлы будут прочитаны. Аналог END {for(i in D) print i} на баше будет:
Bash
1
2
3
for i in ${!D[@]};
  do echo $i;
done
1
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
16.10.2020, 20:14

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

Удаление лишних строк таблицы, парсер PS
Здравствуйте! Имеется скрипт парсера некой веб - страницы, содержащую таблицу. Таблица извлечена из...

Программное удаление лишних строк таблицы DataGridView
Имеется программа. При считывании из файла таблица заполняется таким образом (рис.1). При нажатии...

Упражнение 1.18 Удаление лишних пробелов, табуляций и строк
Упражнение 1.18. Напишите программу, которая будет в каждой вводимой строке заменять стоящие подряд...

Удаление лишних пустых строк и пробелов на конце строки
open(FIL,&quot;azaz.txt&quot;); my @s =&lt;FIL&gt;; close FIL; for ($i=0; $i &lt;= 9; $i++) { if ( length( $s ) &gt;...

Удаление лишних строк в Excel которые далеко внизу
Файл весит 7-8мб , а должен по идее 2,5-3+- раньше примерно так и весил, если не меньше увидел что...

Поиск начала таблицы на листе и удаление лишних строк над таблицей
Добрый день! Пожалуйста, подскажите, каким образом можно организовать поиск начала таблицы с...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2020, vBulletin Solutions, Inc.