× К оглавлению На главную Об авторе

Дата и время публикации:    

Проблема и решение

1. Суть проблемы

Формат представления табличных данных CSV, который детально описан в RFC-4180, широко используется в качестве отчета работы аппаратных-программных средств, реализующих некий рабочий или технологический процесс, результатом которого является некая совокупность текстовых и числовых значений, представленных порой различными форматами табличных данных.

Как, например, в случае с результатом работы синтаксического анализатора fawfinder [3.1], как показано в дампе 1.1

Листинг 1.1

$ flawfinder --csv --context --minlevel=4 test.c > test_c.csv && \
test -s test_c.csv && \
echo "Success."

Который в результате синтаксического анализа исходного кода test.c [3.2] создаст файл-отчет в формате CSV, требующий комплексного подхода при извлечении табличных значений данных и имеющие сложный формат представления, с использованием разделителей (Comma Separated Values) .

Суть проблемы такой нетравиальной обработки CSV файла test_c.csv является неравномерное распределение разделителей в виде запятой (,) вместе с двойными кавычками ("), окаймляющими текст и экранирующие в нем символы резделителя, как показано в (небольшом фрагменте) файла test_c.csv, в дампе 1.2

Листинг 1.2

...
test.c,32,2,5,buffer,gets,"Does not check for buffer overflows (CWE-120, CWE-20)",Use fgets() instead, ….
test.c,56,3,5,buffer,strncat,"Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120)","Consider … 
...

Из которого видно, что нет и не может быть никакой закономерности в распределение кавычек для экранирования текста, как и внутри него символов запятых (,). Поэтому простое извлечение с использованием SHELL команды CUT(1) уже не хватало. Впрочем, как и тратить время на погружение в дебри AWK(1) или написание небольшой консольной программки на С . Следовательно, на мой взгляд, правильным решением было обратить взор на Python

2. Решение

2.1 Модуль CSV

Таким решением стало применение файла сценария, написанным на языке Python, вместе с модулем csv [3.3], который позволил быстро решить проблему, связанную с нетривиальной обработкой CSV файла test_c.csv [3.2]

Модуль CSV реализует класс объектов, позволяющий писать и читать табличные значения данных в формате CSV. При этом сам модуль от программиста не потребует каких-либо особых знаний в использовании формата CSV, чтобы экспортировать / импортировать данные в/из CSV-файла в соответствии с принятым по умолчанию практическими всеми офисными наборами программ стилем "excel", называемым так же в различной технической литературе диалектом (dialect), или определяемый им собственноручно. Подключается модуль с используем оператора import, как показано ниже.

import csv

К тому же, модуль csv является самодостаточным, если планируется производить с табличными данными только операции открытия,чтения и записи с файлом CSV.

2.2 Диалекты обработки данных и управление ими

По умолчанию, как уже было сказано выше, обработка табулированных данных модулем csv производится с использованием установленного по умолчанию диалекта данных "excel" [3.4], как показано в листинге 2.2.1

Листинг 2.2.1

class excel(Dialect):
    delimiter = ','
    quotechar = '"'
    doublequote = True
    skipinitialspace = False
    lineterminator = '\r\n'
    quoting = QUOTE_MINIMAL

Который, как видно из листинга класса excel имеет базовый класс Dialect, как показано в листинге 2.2.2

Листинг 2.2.2

class Dialect:
    # placeholders
    delimiter = None
    quotechar = None
    escapechar = None
    doublequote = None
    skipinitialspace = None
    lineterminator = None
    quoting = None

Кроме того, перечисленные параметры можно указывать, перечислять, отдельно в конструкторе при создании читателя (cvsreader) или писателя (csvwriter) для уточнения применяемого диалекта по ходу пьесы без переопределения определяющего его класса.

Параметры отдельно применяемые внутри диалекта понимаются как :

Параметр quoting может позволять устанавливать следующие режимы экранированием полей (значений табличных данных):

2.3 Операция импорта (чтения)

Производится путем создания читателя (csvreader) с использованием отдельной функции [3.5], предоставляемой модулем csv, как показано в листинге 2.3.1

Листинг 2.3.1

CSV readers are created with the reader factory function:
csvreader = csv.reader(iterable [, dialect='excel']
             [optional keyword args])

Которая возвращает прочитанные строки из интегрируемого объекта, передаваемого в единственным своем аргументе . При этом аргументы dialect и ключевые уточняющие его параметры (optional keyword args) являются необязательными чем и воспользуемся, чтобы прочитать проблемный файл test_c.csv, как показано 2.3.2

Листинг 2.3.2

...
File_col        = 0
Line_col        = 1
Column_col      = 2
Level_col       = 3
Category_col    = 4
Name_col        = 5
Warning_col     = 6
Suggestion_col  = 7
Note_col        = 8 
...
    with open(fl_dst, newline='') as csvfile: 
         csvreader = csv.reader(csvfile, delimiter=',')
         for row in csvreader:
             print ( '\'%s\'' % row[File_col], '\'%s\'' % row[Line_col], '\'%s\'' % row[Column_col], '\'%s\'' % row[Level_col], '\'%s\'' % row[Category_col], '\'%s\'' % row[Name_col], '\'%s\'' % row[Warning_col], '\'%s\'' % row[Suggestion_col], '...' )    

В результате выполнения которого получим строки с осознанными значениями полей, перечисляемыми через запятую и окаймленные одинарными кавычками ('), как это делает встроенная функция print, фрагмент с результатом работы который показан в дампе 2.3.3

Дамп 2.3.3

...
'examples-1.1/test.c' '32' '2' '5' 'buffer' 'gets' 'Does not check for buffer overflows (CWE-120, CWE-20)' 'Use fgets() instead' ...
'examples-1.1/test.c' '56' '3' '5' 'buffer' 'strncat' 'Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120)' 'Consider strcat_s, strlcat, snprintf, or automatically resizing strings' ...
... 

При этом, как видно из только что полученного результата, проблема, связанная с нетривиальной обработкой CSV-файла test_c.csv, перестала существовать.

Также хочется обратить на выделенную жирным и применяемую программную конструкцию "with … as", которая за собой скрывает целый блок команд и является оберткой исполняемого кода, немедленно прерываемого в случае возникновения ошибки вместе с принудительным завершением выполнения остального кода файла-сценария [3.6].

2.4 Операция экспорта (записи)

Производится путем создания писателя (csvwriter) и двух методов writerow() и writerows() [3.7], которые осуществляют экспорт одной строки или несколько строк соответственно, как показано в листинге 2.4.1

Листинг 2.4.1

csvwriter = csv.writer(iterable [, dialect='excel']
             [optional keyword args])
csvwriter.writerow(row)
csvwriter.writerows(someiterable)

При этом, однострочную запись с writerow() можно использовать для формирвания нового CSV-файла, как показано в листинге 2.4.2

Листинг 2.4.2

...
with open('test_c.new.csv', 'a+',newline='') as csvfile: 
         csvwriter = csv.writer(csvfile, delimiter=';')
     csvwriter.writerow([row[File_idx],row[Line_idx],row[Column_idx],row[CWEs_idx],row[Level_idx],row[Category_idx],row[Name_idx],row[Warning_idx],...]) 
         nerrors += 1
...

В результате выполнения которого будет создан файл test_c.new.csv, содержащий записанные выборочно поля строк, ранее прочитанных csvreader из файла test_c.сsv. Результат операции экспорта данных показан в листинге 2.4.3

Листинг 2.4.3

...
test.c;32;2;CWE-120, CWE-20;5;buffer;gets;Does not check for buffer overflows (CWE-120, CWE-20);" gets(f);"
test.c;56;3;CWE-120;5;buffer;strncat;Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120);"  strncat(d,s,sizeof(d)); /* Misuse - this should be flagged as riskier. */"
...

3. Библиография

3.1 Flawfinder – cканер лексического анализа на потенциальные уязвимости исходного кода

3.2 Flawfinder. Тестовый файл исходного кода test.c

3.3 Python. The module csv

3.4 Python. The module csv. Managing Different Dialects

3.5 Python. The module csv. Reader Objects

3.6 The Python Language Reference. Compound statements

3.7 Python. The module csv. Writer Objects

Сайт разработан в соответствии с рекомендациями консорциума W3C для языка разметки HTML5.

Об авторе можно прочитать здесь.

Copyright © 2015-2019 Андрей Ржавсков