Извлеките информацию между двойными кавычками в .csv

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

У меня есть проблемы со скриптом, который анализирует .csv файл

Информация о .csv:

#1,13/8/2020,[email protected],[email protected],,Тема,"Дорогой друг,

Информация была обновлена. Пожалуйста, войдите в приложение, чтобы просмотреть до 30 августа 2020 года. Спасибо.

С наилучшими пожеланиями,
г-н Мак",В ожидании,13/8/2020 12:35

Вот как информация должна быть разделена:
MsgID,Дата,Кому,Копия,Скрытая Копия,Тема,Текст,Статус,Время записи

MsgID=#1
Дата=13/8/2020
[email protected]
[email protected]
Скрытая Копия=
Тема=Тема
Текст=Дорогой друг,
Информация была обновлена. Пожалуйста, войдите в приложение, чтобы просмотреть до 30 августа 2020 года. Спасибо.
С наилучшими пожеланиями,
г-н Мак
Статус=В ожидании
Время записи=13/8/2020 12:35

Проблемы, с которыми я сталкиваюсь, связаны с текстом тела по двум причинам: запятая “,” в тексте, которая ломает скрипт, и другая причина – переносы строк в тексте.

Вот скрипт, который я делал:

#!/bin/bash

export TIMESTAMP="$( date '+%d/%m/%Y %H:%M:%S' )"
INPUT=/tmp/test.csv
OUTPUT=/tmp/test.csv.out
OLDIFS=$IFS
IFS=','
[ ! -f $INPUT ] && { echo "$INPUT файл не найден"; exit 99; }
while read msgid dat to cc bcc subject body status timesta
do
        echo "MSG ID : $msgid" 
        echo "Дата : $dat"
        echo "Кому : $to"
        echo "Копия : $cc"
        echo "Скрытая Копия : $bcc"
        echo "Тема : $subject"
        echo "Текст : $body"
        echo "Статус : $status"
        echo "Время записи : $timesta"
echo $body | mail -s "$subject" $to -c $cc -b $bcc
printf "$msgid,$dat,$to,$cc,$bcc,$subject,$body,Отправлено,$TIMESTAMP" >> $OUTPUT
done < $INPUT
IFS=$OLDIFS

Оболочка – это просто очень плохой инструмент для анализа текста. Вы должны использовать его только для самых простых задач, и, вероятно, даже в этом случае не стоит. Это медленно, неэффективно, его очень сложный синтаксис делает его подверженным ошибкам, и ему не хватает самых основных инструментов обработки текста. К тому же, CSV – это сложный формат, который позволяет использовать вложенные и многострочные записи. Попытка проанализировать файл CSV в оболочке просто приведет к проблемам.

Поэтому используйте для этого соответствующий язык программирования с поддержкой анализа CSV. Например, на Python:

#!/bin/python3
import csv
import sys

with open(sys.argv[1], newline="") as csvfile:
    fieldnames = ("MsgID","Дата","Кому","Копия","Скрытая Копия",
                  "Тема","Текст","Статус","Время записи")
    reader = csv.reader(csvfile, delimiter=",")
    for row in reader:
        for fieldName, value in zip(fieldnames,row):
            print("%s: %s" % (fieldName,value))

Я сохранил вышеуказанный скрипт как foo.py, а затем:

MsgID: #1
Дата: 13/8/2020
Кому: [email protected]
Копия: [email protected]
Скрытая Копия: 
Тема: Тема
Текст: Дорогой друг,

Информация была обновлена. Пожалуйста, войдите в приложение, чтобы просмотреть до 30 августа 2020 года. Спасибо.

С наилучшими пожеланиями,
г-н Мак
Статус: В ожидании
Время записи: 13/8/2020 12:35

Как вы можете видеть, он правильно распознал все поля. Таким образом, чтобы также отправить почту, вы можете сделать что-то подобное (адаптировано отсюда):

#!/bin/python3
import csv
import sys
import subprocess
import os

def send_message(to, cc, bcc, subject, body):
    try:
        process = subprocess.Popen(['mail', '-s', subject, '-c', cc, '-b', bcc, to],
                                   stdin=subprocess.PIPE)
    except Exception as error:
      print(error)
    process.communicate(body)


with open(sys.argv[1], newline="") as csvfile:
    reader = csv.reader(csvfile, delimiter=",")
    for row in reader:
        (msgID, date, to, cc, bcc, subj, body, status, timestamp) = row
        send_message(to, cc, bcc, subj, body)

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Вы, кажется, используете BSD mail на основе предоставленных вами параметров. У меня нет доступа к рабочей системе с установленным этим инструментом, поэтому я не смог протестировать приведенный выше скрипт для отправки почты. Тем не менее, он должен хотя бы служить хорошим началом.

Вы можете использовать инструмент Miller (https://github.com/johnkerl/miller), специализированный для работы с структурированными текстовыми данными.

Например, начиная с этого файла input.txt

#1,13/8/2020,[email protected],[email protected],,Тема,"Дорогой друг,

Информация была обновлена. Пожалуйста, войдите в приложение, чтобы просмотреть до 30 августа 2020 года. Спасибо.

С наилучшими пожеланиями,
г-н Мак",В ожидании,13/8/2020 12:35

и запустив

mlr --implicit-csv-header --c2x cat then label MsgID,Дата,Кому,Копия,Скрытая Копия,Тема,Текст,Статус,Время записи input.txt

вы получите

MsgID     #1
Дата      13/8/2020
Кому      [email protected]
Копия     [email protected]
Скрытая Копия
Тема      Тема
Текст     Дорогой друг,

Информация была обновлена. Пожалуйста, войдите в приложение, чтобы просмотреть до 30 августа 2020 года. Спасибо.

С наилучшими пожеланиями,
г-н Мак
Статус    В ожидании
Время записи 13/8/2020 12:35

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

mlr --implicit-csv-header --c2x cat then label MsgID,Дата,Кому,Копия,Скрытая Копия,Тема,Текст,Статус,Время записи then put '$Текст=gsub($Текст,"\n"," ")' input.txt

чтобы получить

MsgID     #1
Дата      13/8/2020
Кому      [email protected]
Копия     [email protected]
Скрытая Копия
Тема      Тема
Текст     Дорогой друг, Информация была обновлена. Пожалуйста, войдите в приложение, чтобы просмотреть до 30 августа 2020 года. Спасибо. С наилучшими пожеланиями, г-н Мак
Статус    В ожидании
Время записи 13/8/2020 12:35

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

Извлечение информации в кавычках из .csv файла

Введение

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

Описание проблемы

В представленном примере .csv файла информация разбивается на следующие поля: MsgID, Date, To, CC, BCC, Subject, Body, Status, Timestamp. Однако текст сообщения, находящийся в поле Body, содержит как запятые, так и переносы строк. Это приводит к некорректной работе скрипта, который использует bash для обработки файла.

Пример .csv файла:

#1,13/8/2020,[email protected],[email protected],,Subject,"Dear Dude,
Information have been updated. Please login to APP to review by 30th August 2020. Thank you.
Best regards,
Mr. Mack",Pending,13/8/2020 12:35

Предложение решения

Для избегания проблем с разбором текста в CSV форматах, рекомендуется использовать языки программирования, которые поддерживают парсинг CSV «из коробки», такие как Python.

Пример на Python

Если у вас установлен Python, вы можете воспользоваться следующим сценарием для корректного извлечения всех полей из .csv:

#!/bin/python3
import csv
import sys
import subprocess

def send_message(to, cc, bcc, subject, body):
    try:
        process = subprocess.Popen(['mail', '-s', subject, '-c', cc, '-b', bcc, to], stdin=subprocess.PIPE)
        process.communicate(body.encode())
    except Exception as error:
        print(error)

if __name__ == "__main__":
    with open(sys.argv[1], newline="") as csvfile:
        reader = csv.reader(csvfile, delimiter=",")
        for row in reader:
            (msgID, date, to, cc, bcc, subj, body, status, timestamp) = row
            print(f"MsgID: {msgID}\nDate: {date}\nTo: {to}\nCC: {cc}\nBCC: {bcc}\nSubject: {subj}\nBody: {body}\nStatus: {status}\nTimestamp: {timestamp}")
            send_message(to, cc, bcc, subj, body)

Пояснение к коду

  1. Импорт библиотек: Импортируем необходимые модули для работы с CSV и отправки почты.
  2. Функция send_message: Запускает команду отправки почты с правильными параметрами.
  3. Чтение .csv файла: Используется csv.reader, чтобы правильно обрабатывать текст с учетом кавычек, запятых и переносов строк.

Альтернативное решение: Использование Miller

Еще одним подходом является использование утилиты Miller, которая оптимизирована для работы со структурированными текстовыми данными. Запуск следующей команды позволит извлечь и вывести нужную информацию:

mlr --implicit-csv-header --c2x cat then label MsgID,Date,To,CC,BCC,Subject,Body,Status,Timestamp input.txt

При этом возможно также убрать переносы строк из текста поля Body:

mlr --implicit-csv-header --c2x cat then label MsgID,Date,To,CC,BCC,Subject,Body,Status,Timestamp then put '$Body=gsub($Body,"\n"," ")' input.txt

Заключение

Выбор правильного инструмента для обработки данных .csv в значительной степени определяет успех итогового результата. Для обработки данных, содержащих сложные текстовые элементы, рекомендуется использовать языки программирования с функциями для работы с CSV, такие как Python, или специализированные инструменты, такие как Miller. Эти подходы помогут избежать распространенных ошибок и упростят работу с текстом, содержащим запятые и переносы строк.

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

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