Фильтрация строк CSV, где определенные поля являются пустыми или непустыми

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

Я пытаюсь отфильтровать строки в CSV файле на основе двух конкретных условий, используя awk:

  1. Поле 2 должно быть пустым и Поле 4 должно быть непустым.
  2. Поле 2 должно быть непустым и Поле 4 должно быть пустым.

Например, рассмотрим файл CSV со следующим содержимым:

"venBio","http://www.venbio.com","","venBio является инвестором, расположенным в Соединенных Штатах, Северная Америка."
"zhenZhou","http://www.zhenzhou.com","",""
"Loren","","","Знаменитая голливудская актриса 1950-х и 1960-х годов"

Я хочу, чтобы скрипт awk сначала выводил:

"Loren","","","Знаменитая голливудская актриса 1950-х и 1960-х годов"

а затем

"zhenZhou","http://www.zhenzhou.com","",""

Я пробовал различные подходы, но не смог правильно отфильтровать данные по этим условиям. Может ли кто-нибудь подсказать мне правильный синтаксис awk для достижения этого?


Попробованные подходы:

awk -F, '($2 == "" && $4 != "")' input.csv

awk -F, '($2 != "" && $4 == "")' input.csv

awk -F, '($2 ~ /^[[:space:]]*$/ && $4 !~ /^[[:space:]]*$/)' input.csv

awk -F, '($2 !~ /^[[:space:]]*$/ && $4 ~ /^[[:space:]]*$/)' input.csv

Вы можете использовать этот awk:

awk -F, -v nul="""" '$2 != nul && $4 == nul {s = s $0 ORS}
$2 == nul && $4 != nul; END {printf "%s", s}' file

"Loren","","","Знаменитая голливудская актриса 1950-х и 1960-х годов"
"zhenZhou","http://www.zhenzhou.com","",""

Предположения:

  • все поля обернуты в двойные кавычки
  • в полях нет встроенных/экранированных двойных кавычек

Если мы используем -F'"' для обозначения разделителя полей ввода, то нам просто нужно помнить, что все поля данных на самом деле являются четными номерами (то есть 1-е поле ссылается на $2, 2-е поле ссылается на $4).

Изменяя и комбинируя первые два скрипта awk автора вопроса:

awk -F'"' '
FNR==NR { if ($4 == "" && $8 != "") print; next }    # обработка 1-го файла
        { if ($4 != "" && $8 == "") print       }    # обработка 2-го файла
' input.csv input.csv

ЗАМЕТКИ:

  • $4 — это 2-е поле данных; $8 — это 4-е поле данных
  • print без аргументов рассматривается так же, как print $0 (то есть выводит всю строку как есть)
  • мы предоставляем две ссылки на входной файл (input.csv), чтобы ограничить использование памяти при генерации выходных данных в нужном порядке

Это генерирует:

"Loren","","","Знаменитая голливудская актриса 1950-х и 1960-х годов"
"zhenZhou","http://www.zhenzhou.com","",""

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

awk -F'","' '($2 == "" && $4 != "\"") || ($2 != "" && $4 == "\"")' file.csv

Поскольку поле $4 является последним, вам все равно нужно учесть эту последнюю двойную кавычку.

The One True Awk поддерживает CSV напрямую, но XOR все еще должен быть реализован как NOT/AND/OR:

awk --csv '(!length($2)&&length($4)) || (length($2)&&!length($4))' input.csv

в результате чего:

"zhenZhou","http://www.zhenzhou.com","",""
"Loren","","","Знаменитая голливудская актриса 1950-х и 1960-х годов"

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

awk --csv '!length($2)&&length($4)' input.csv
awk --csv 'length($2)&&!length($4)' input.csv

в результате чего:

"Loren","","","Знаменитая голливудская актриса 1950-х и 1960-х годов"
"zhenZhou","http://www.zhenzhou.com","",""

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

Для решения вашей задачи по фильтрации строк в CSV-файле с использованием утилиты awk, мы можем использовать следующую стратегию. Задача заключается в том, чтобы отфильтровать строки по двум условиям:

  1. Поле 2 должно быть пустым (null), а поле 4 — непустым (non-null).
  2. Поле 2 должно быть непустым (non-null), а поле 4 — пустым (null).

Мы будем использовать awk с заданным разделителем. Поскольку в вашем случае поля заключены в кавычки, логично будет использовать awk с указанием разделителя -F'"'.

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

awk -F'","' '
{
    if ($2 == "" && $4 != "\"") {
        print $0
    }
}
' input.csv

awk -F'","' '
{
    if ($2 != "" && $4 == "\"") {
        print $0
    }
}
' input.csv

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

Таким образом, полная последовательность команд будет выглядеть так:

awk -F'","' '
{
    if ($2 == "" && $4 != "\"") {
        print $0
    }
}
' input.csv

awk -F'","' '
{
    if ($2 != "" && $4 == "\"") {
        print $0
    }
}
' input.csv

Объяснение:

  • -F'","': указывает, что поля отделены не только запятой, но и кавычками, что позволяет корректно обрабатывать строки.
  • if ($2 == "" && $4 != "\""): проверяет первое условие, где поле 2 пусто, а поле 4 заполнено.
  • if ($2 != "" && $4 == "\""): проверяет второе условие, где поле 2 заполнено, а поле 4 пусто.
  • print $0: выводит всю строку.

После выполнения данной последовательности вы получите следующий вывод:

"Loren","","","A famous Hollywood actress from the 1950s and 1960s"
"zhenZhou","http://www.zhenzhou.com","",""

Таким образом, используя указанные команды awk, вы сможете эффективно фильтровать строки в вашем CSV-файле на основании заданных условий. Если у вас есть дополнительные вопросы по данной теме, не стесняйтесь обращаться!

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

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