1 (edited by Serhij 2014-11-12 12:23:46)

Topic: Импорт из csv

Здравствуйте.
Нужна помощь в исправлении скрипта.
Имеем:

Основная таблица: "zapyty"
содержит столбцы:
record_count (СЧЕТЧИК)
data (ДАТА)
zmist (ТЕКСТ)
dokument (ЦЕЛОЕ ЧИСЛО)
dodatok (ЦЕЛОЕ ЧИСЛО)
adresat (ТЕКСТ)
id_user (СВЯЗЬ)
prymitka (ТЕКСТ)

Словарь: "user"
содержит столбцы:
name (ТЕКСТ)
admin (ДА/НЕТ)

На кнопку повешан скрипт импорта данных из файла csv в основную таблицу:

procedure Form1_btnImport_OnClick (Sender: string; var Cancel: boolean);
var
   OpenDialog: TOpenDialog;
   sl: TStringList;
   arrStr: array of string;
   i,c: integer;
   counter: string;
   data: string;
   zmist: string;
   dokument: string;
   dodatok: string;
   adresat: string;
   userID: string;
   prymitka: string;
begin
     OpenDialog := TOpenDialog.Create(Form1);
     if OpenDialog.Execute then
     begin
          sl := TStringList.Create;
          sl.LoadFromFile (OpenDialog.FileName);
          c := sl.Count - 1;
          for i := 0 to c do
          begin
          arrStr:= SplitString(sl[i], ';');

          // record_count
          counter := '"' + arrStr[0] + '"';

          // data
          if arrStr[1]<>'' then
          data := '"'+ FormatDateTime('yyyy-MM-DD 00:00:00.000', StrToDate(arrStr[1])) + '"';

          // zmist
          zmist := '"' + arrStr[2] + '"';

          // dokument
          dokument := '"' + arrStr[3] + '"';

          // dodatok
          dodatok := '"' + arrStr[4] + '"';

          // adresat
          adresat := '"' + arrStr[5] + '"';

          // id_user
          userID := SQLExecute ('Select id From user WHERE name LIKE "' + arrStr[6] + '"');

          // prymitka
          prymitka := '"' + arrStr[7] + '"';

          SQLExecute ('INSERT INTO zapyty (record_count, data, zmist, dokument, dodatok, adresat, id_user, prymitka) VALUES ('+ counter +','+ data +','+ zmist +','+ dokument +','+ dodatok +','+ adresat +','+ userID +','+ prymitka +');');
          end;

          sl.Free;
          Form1.TableGrid1.dbUpdate;
          ShowMessage('Импорт завершен');
     end;
     OpenDialog.Free;
end;

такой скрипт выдаёт ошибку "Variant or safe array index out of bounds".

Re: Импорт из csv

Разобрался. Был кривой csv файл.

Re: Импорт из csv

Теперь скрипт ругается на записи, которые содержат кавычки (") и строки с такими записями не вставляет в таблицу.
Подскажите, как это можно исправить?

Re: Импорт из csv

Одинарные каавычки (") в csv файле надо заменить на двойные ("").
Как это можно сделать в процессе выполнения скрипта?

Re: Импорт из csv

Это можно сделать так

// dokument
dokument := '"' +  ReplaceStr(arrStr[3], '"', '""') + '"';
Dmitry.

Re: Импорт из csv

спасибо

7 (edited by kunar80 2014-11-15 14:18:39)

Re: Импорт из csv

Подскажите, как переписать этот код импорта

procedure frmChoice_bImportNAF_OnClick (Sender: string; var Cancel: boolean);
var
   OpenDialog: TOpenDialog;
   sl: TStringList;
   arrStr: array of string;

   i,c: integer;

   sid_sked: string; //опись
   sDocNumNAF: string; //номер дела
   sDocNameNAF: string; //название
   sid_year: string; //год формирования
   sid_period: string; //срок хранения
   sPagesNAF: string; //количество страниц
   sNoteNAF: string; //примечание

   YY, MM, DD: string;


begin

     OpenDialog := TOpenDialog.Create(frmChoice);
     if OpenDialog.Execute then
     begin
          sl := TStringList.Create;
          sl.LoadFromFile (OpenDialog.FileName); ///открытие файла




          c := sl.Count - 1;
          for i := 1 to c do
          begin
               arrStr := SplitString(sl[i], ';');


               //0 sid_sked
               if arrStr[0] <> '' then
               begin
                    sid_sked := SQLExecute ('SELECT id FROM sked WHERE sked LIKE "' + arrStr[0] +'"');
                    if sid_sked = '' then
                    begin
                         SQLExecute ('INSERT INTO sked (sked) VALUES ("'+ arrStr[0] +'");');
                         sid_sked := IntToStr(Last_Insert_id('sked'));
                         if sid_sked = '-1' then sid_sked := 'NULL';
                    end;
               end else sid_sked := 'NULL';


               //1 sDocNumNAF
               if arrStr[1]<>'' then sDocNumNAF := '"'+arrStr[1]+'"' else sDocNumNAF := 'NULL';


               //2 sDocNameNAF
               if arrStr[2]<>'' then sDocNameNAF := '"' +  ReplaceStr(arrStr[2], '"', '""') + '"' else sDocNameNAF := 'NULL';


               //3 sid_year
               if arrStr[3] <> '' then
               begin
                    sid_year := SQLExecute ('SELECT id FROM year WHERE year LIKE "' + arrStr[3] +'"');
                    if sid_year = '' then
                    begin
                         SQLExecute ('INSERT INTO year (year) VALUES ("'+ arrStr[3] +'");');
                         sid_year := IntToStr(Last_Insert_id('year'));
                         if sid_year = '-1' then sid_year := 'NULL';
                    end;
               end else sid_year := 'NULL';


               //4 sid_period
               if arrStr[4] <> '' then
               begin
                    sid_period := SQLExecute ('SELECT id FROM period WHERE period LIKE "' + arrStr[4] +'"');
                    if sid_period = '' then
                    begin
                         SQLExecute ('INSERT INTO period (period) VALUES ("'+ arrStr[4] +'");');
                         sid_period := IntToStr(Last_Insert_id('period'));
                         if sid_period = '-1' then sid_period := 'NULL';
                    end;
               end else sid_period := 'NULL';


               //5 sPagesNAF
               if arrStr[5]<>'' then sPagesNAF := '"'+arrStr[5]+'"' else sPagesNAF := 'NULL';


               //6 sNoteNAF
               if arrStr[6]<>'' then sNoteNAF := '"'+arrStr[6]+'"' else sNoteNAF := 'NULL';



               SQLExecute ('INSERT INTO one (id_sked, [docNumNAF], [docNameNAF], id_year, id_period, [pagesNAF], [noteNAF]) VALUES ('+
               sid_sked +','+
               sDocNumNAF +','+
               sDocNameNAF +','+
               sid_year +','+
               sid_period +','+
               sPagesNAF +','+
               sNoteNAF +
               ');');


               frmChoice.Label8.Caption := IntToStr(i) + ' of ' + IntToStr(c);
               Application.ProcessMessages;
          end;



          sl.Free;
          UpdateDatabase('sked');
          UpdateDatabase('year');
          UpdateDatabase('period');
          frmChoice.TableGrid1.dbUpdate;
     end;
     OpenDialog.Free;
begin
     frmChoice.bSearch1.Click;  ////!!!!!Нажатие на кнопку ПОИСК (при этом видимые записи таблицы обновляются)
end;

end;

чтобы вместо диалога выбора файла открывалась конкретная предсозданная папка с шаблонами csv,

begin
OpenFile('d:\Archive 1.01\ImportCSV');
end;

в которой лежат несколько разных шаблонов csv по количеству кнопок импорта в проекте?
Т.е., если у меня есть три грида, и каждому из них соответствует своя кнопка "Импорт", то при клике на кнопке пользователь должен попасть в папку, в которой лежат три файла csv и выбрать нужный.

Не боги горшки лепят!

Re: Импорт из csv

у объекта TOpenDialog есть свойство InitialDir, которое позволяет задать папку, которая будет открываться по умолчанию

...
 OpenDialog := TOpenDialog.Create(frmChoice);
 OpenDialog.InitialDir := 'd:\CVS'; 
     if OpenDialog.Execute then
     begin
...
Dmitry.

Re: Импорт из csv

Здравствуйте. Как сделать импорт вот таких данных:

'
Пусть фантазии и грезы
В жизни воплощаются!
Пусть приятные моменты
Чаще приключаются!
';1;П00002;2

то есть в таблице 4 колонки Текст, Группа, Номер, Счетчик. И поле Текст многострочное. Как сделать, чтобы в первую колону попадал текст между разделителями текста ( '  ' ) .

Re: Импорт из csv

Rebrovvv
такие данные сперва необходимо привести к стандартному CSV формату, например в любом текстовом редакторе переводы строк заменить на спец. символ, например на #CRLF, т.о. много строчный текст будет одной длинной строкой, затем при импорте с помощью скрипта заменять данный символ обратно на перевод строки (#13)


можете приложить ваш проект (zip файл без exe и dll) и файл для импорт, постараюсь помочь.

Dmitry.

Re: Импорт из csv

Отправил проект Вам на почту.

Re: Импорт из csv

Огромное Спасибо. Все работает. Ваша программа просто супер!
Может кому будет полезен данный скрипт:

procedure Form1_Button14_OnClick (Sender: string; var Cancel: boolean);
var
   OpenDialog: TOpenDialog;
   sl: TStringList;
   arrStr: array of string;
   i,c: integer;
   sLine: string;
   counter: string;
   text: string;
   kategory: string;
   number: string;
begin
     OpenDialog := TOpenDialog.Create(Form1);
     if OpenDialog.Execute then
     begin
          sl := TStringList.Create;
          sl.LoadFromFile (OpenDialog.FileName);
          c := sl.Count - 1;
          sLine := '';

          for i := 0 to c do
          begin
              if (Length(sl[i])>0) and (sl[i][1]=';') then
              begin
                 sLine := sLine + sl[i];
                 arrStr:= SplitString(sLine, ';');

                  if arrStr[0][1]=' ' then
                  Delete(arrStr[0], 1, 2);

                  // Пожелание
                  text := '''' + arrStr[0] + '''';



                  // Категория
                  kategory := arrStr[1];

                  // №
                  number := '''' + arrStr[2] + '''';

                  // record_count
                  counter := arrStr[3];
    
                  SQLExecute ('INSERT INTO pozhelaniya (text, id_pozhelaniyakategoriya, textid, record_count) VALUES ('+ text +','+ kategory +','+ number +','+ counter +');');
                  sLine := '';
              end else
                  sLine := sLine + sl[i]+#13#10;


              Form1.Label19.Caption := 'Обработано '+ IntToStr(i)+ ' строк из ' + IntToStr(c);
              Application.ProcessMessages;
          end;

          sl.Free;
          Form1.TableGrid3.dbUpdate;
          ShowMessage('Импорт завершен');
     end;
     OpenDialog.Free;
end;

13 (edited by kunar80 2015-09-19 07:08:55)

Re: Импорт из csv

Доброго всем дня!
Вот таким скриптом организуется импорт в таблицу данных АКТ-ПАПКА-ДОКУМЕНТ.

// id_Act - текстовое содержимое первого столбца содержится в arrStr[0]
if arrStr[0] <> '' then
begin
   ActID := SQLExecute ('SELECT id FROM act WHERE act LIKE "' + arrStr[0] +'"');
   if ActID = '' then
     begin
        SQLExecute ('INSERT INTO act (act) VALUES ("'+ arrStr[0] +'");');
        ActID := IntToStr(Last_Insert_id('act'));
        if ActID = '-1' then ActID := 'NULL';
     end;
end else ActID := 'NULL';

// id_Folder - текстовое содержимое второго столбца содержится в arrStr[1]
if arrStr[1] <> '' then
begin
   FolderID := SQLExecute ('SELECT id FROM folder WHERE folder LIKE "' + arrStr[1] +'"');
   if FolderID = '' then
      begin
         SQLExecute ('INSERT INTO folder (folder) VALUES ("'+ arrStr[1] +'");');
        FolderID := IntToStr(Last_Insert_id('folder'));
        if FolderID = '-1' then FolderID := 'NULL';
      end;
end else FolderID := 'NULL';

// Document -  текстовое содержимое третьего столбца содердижится в arrStr[2]
if arrStr[2]<>'' then sDocument := '"'+arrStr[2]+'"' else sDocument := 'NULL';

               SQLExecute ('INSERT INTO document (id_act, id_folder, [document]) VALUES ('+
               ActID +','+
               FolderID +','+
               sDocument +
               ');'); // с помощью SQL запрос вставляем данные в БД

Проблема в следующем. Помимо номера акт имеет ещё и дату (поле date в таблице act). Актов с одинаковыми номерами может быть несколько, но с разными датами (за разные годы).  Если не указана дата, а только номер, то при загрузке новые записи привязываются к тому акту, у которого наименьший ID.
Как в этот скрипт добавить дату акта? Файл CSV соответственно должен иметь колонки АКТ-ДАТА--ПАПКА-ДОКУМЕНТ

Post's attachments

Attachment icon CSV_Doc.rar 12.52 kb, 508 downloads since 2015-09-19 

Не боги горшки лепят!

Re: Импорт из csv

Давно Вас Дмитрий не терроризировал, а тут Кунар80 опередил, может Вы поможете, а может кто другой -  суть в следующем  имею рабочий скрипт по восстановлению базы из csv, но была проблема с переносом информации из поля memo, так как хранилась в многострочном  виде, и сохраняло только кусок текста до переноса строки.  Увидел эту тему, пытался применить пост выше на 1 от этого, так как  я понял проблема была однотипная но никак ее решить у меня не получается, может окажете легкую помощь? (восстанавливать пытался в тесте данные экспортированные в ексель, а затем сохраненные в csv)
текст листинга с комментариями рабочего кода но с описанной выше проблемой:

информация для восстановления из поля memo хранится в строке  if arrStr[4]<>'' then sPrimechanie := '"' + arrStr[4] + '"' else sPrimechanie := 'NULL';

procedure OTKAZNIE_MATERIALI_ImportVidMat_OnClick (Sender: string; var Cancel: boolean);  ///ИМПОРТ ДАННЫХ ИЗ CSV ФАЙЛА ДЛЯ РЕАЛИЗАЦИИ ПЕРЕНОСА И БЭКАПА
var
   OpenDialog: TOpenDialog; // объект для диалога выбора файла
   sl: TStringList; // объект, представляющий из себя текстовый список
   arrStr: array of string; // массив, в который будет возвращаться результат функции SplitString

   sID: string;          // ПЕРЕМЕННАЯ ID
   i,c: integer;         // числовые переменные для цикла
   sVidMat: string;      // переменная - вид материала
   sMaterial: string;    // переменная - номер материала
   sGod: string;         // переменная - год материала
   sDataVidachi: string; // переменная - дата выдачи материала
   sFio: string;         // переменная - фио получателя
   sSluzbi: string;      // переменная - служба получателя
   sPrimechanie: string; // переменная - примечение
   sNavsegda: string;    // переменная - если выдан навсегда, либо приобщен к чему либо
   srecord_count: string;
   sval: string;
   sYesNo: string;

begin
      OpenDialog := TOpenDialog.Create(OTKAZNIE_MATERIALI); // создаем диалог выбора файла
      //OpenDialog.InitialDir := 'd:\Archive 1.01\ImportCSV';  либо можно изменить на фыбор по умолчанию
      if OpenDialog.Execute then // запускаем диалог выбора файла, если результат выполенения True, значит файл был выбран

      begin
          sl := TStringList.Create; // создаем объект - текстовый список
          sl.LoadFromFile (OpenDialog.FileName); // загружаем в него csv файл, который пользователь выбрал через диалог выбора файла

          c := sl.Count - 1; // в переменной c будет содержаться количество строк в csv файле
          for i := 0 to c do  // запускаем цикл, чтобы пройтись по всем строчкам csv файла, который загрузили в объект sl (TStringList)

          begin
               arrStr := SplitString(sl[i], ';'); // sl[i] возвращает строку из csv файла, которую функция SplitString разделяет на столбцы. В данном csv файле в качестве разделителя столбцов используется знак ;
                //if arrStr[0]<>'' then srecord_count:= '"' + arrStr[0] + '"' else srecord_count:= 'NULL';
                //if arrStr[0]<>'' then sID          := '"' + arrStr[0] + '"' else sID          := 'NULL';
                if arrStr[0]<>'' then sMaterial    := '"' + arrStr[0] + '"' else sMaterial    := 'NULL';
                if arrStr[1]<>'' then sGod         := '"' + arrStr[1] + '"' else sGod         := 'NULL';

                if arrStr[2]<>'' then // если данные есть
                sDataVidachi := '"'+ FormatDateTime('yyyy-MM-DD 00:00:00.000', StrToDate(arrStr[2])) + '"' // приводим дату к формату, который необходим для записи в БД
                else sDataVidachi := 'NULL'; // иначе значение NULL

                if arrStr[3]<>'' then sFio         := '"' + arrStr[3] + '"' else sFio         := 'NULL';
                if arrStr[4]<>'' then sPrimechanie := '"' + arrStr[4] + '"' else sPrimechanie := 'NULL';

                sSluzbi := SQLExecute ('SELECT id FROM sluzba WHERE sluzbi LIKE "' + arrStr[5] +'"'); // и
                if sSluzbi = '' then sSluzbi := 'NULL';

                sVidMat := SQLExecute ('SELECT id FROM vidmateriala WHERE vidmat LIKE "' + arrStr[6] +'"'); // и
                if sVidMat = '' then sVidMat := 'NULL';

                if arrStr[7]<> '' then
           begin
                if arrStr[7] = 'Да' then sYesNo :='1';
                if arrStr[7] = 'Нет' then sYesNo :='0';
           end else sYesNo:='NULL';

                if arrStr[8]<>'' then srecord_count := '"' + arrStr[8] + '"' else srecord_count := 'NULL';

               SQLExecute ('INSERT INTO OTKAZNIE ( [MATERIAL], [GOD], [DATA_VIDACHI], [FIO],[PRIMECHANIE],id_SLUZBA, id_VIDMATERIALA, [NAVSEGDA], [record_count]) VALUES ('+
               sMaterial +','+ sGod +','+ sDataVidachi +','+ sFio +','+ sPrimechanie +','+ sSluzbi +','+ sVidMat +','+ sYesNo +','+ srecord_count + ');');


                //проверяем, для избежания дубликатов, данная проверка не обязательна, и зависит от вашей ситуации
              // sval := SQLExecute('SELECT id FROM otkaznie WHERE (Material = ' + arrStr[0] + ') AND (GOD = ' +  arrStr[1] + ');');

             // if sval = '' then // если в переменной sval - пусто, значит SQL запрос ничего не вернул, и дубликата данных нет
                // SQLExecute ('INSERT INTO otkaznie (Material, GOD ) VALUES ('+ arrStr[0] + '), ('+ arrStr[1] + ');'); // с помощью SQL запрос вставляем данные в БД


               OTKAZNIE_MATERIALI.ImportCSV.Caption := IntToStr(i) + ' of ' + IntToStr(c); // выводим в компонент надписи, какое количество строк с данными обработано
               Application.ProcessMessages; // необходимо, чтобы надпись в Label один обновилась
          end;

          sl.Free; // уничтожаем объект, после работы с ним
          OTKAZNIE_MATERIALI.REZULTAT.dbUpdate; // заставляем TableGrid обновить данные
     end;
     OpenDialog.Free; // уничтожаем объект, после работы с ним
end;

//procedure OTKAZNIE_MATERIALI_REZULTAT_OnColumnResize (Sender: string; ACol: Integer);
//begin

   // OTKAZNIE_MATERIALI_REZULTAT_OnChange ('');

//end;

Re: Импорт из csv

wertyby
покажите как выглядит ваш csv файл, если я правильно понял, то он содержит переносы строк в некотором поле.


в любом случае проблему можно решить заменой переноса строк спецсимволом, например так

s:= ReplaceStr(s, #13#10, '\crlf\');

затем перед импортом проделать обратную операцию

s:= ReplaceStr(s, '\crlf\', #13#10);
Dmitry.

Re: Импорт из csv

kunar80
Как импортировать дату можете посмотреть здесь:
http://myvisualdatabase.com/forum/viewt … 8959#p8959

Dmitry.

17 (edited by wertyby 2015-09-20 10:32:39)

Re: Импорт из csv

Дмитрий читал при переносы строк, в итоге пытался в csv менять разделитель "|" на "#13#10" - не помогло.  Если не очень затруднит гляньте csv файл и кусок скрипта аналогичный выложенному но где я пытался вставить кусок примера  Rebrovvv.  строки кода из примера которые пытался вставлять отмечены "//++++++++++++++++++++++" . Никаких ошибок при работе не выдает, выводит что импортировано например 9 строк, но ничего более не происходит.

https://drive.google.com/file/d/0B1hkxd … sp=sharing

И еще можно закоментировать эти строки, никак полность не пойму их смысл:

begin
              if (Length(sl[i])>0) and (sl[i][1]=';') then
              begin
                 sLine := sLine + sl[i];
                 arrStr:= SplitString(sLine, ';');

                  if arrStr[0][1]=' ' then
                  Delete(arrStr[0], 1, 2);

Re: Импорт из csv

wertyby
в CSV файле не должно быть переносов строки для отдельных полей.
Воспрользуйтесь программой notepad++ (продвинутый блокнот)


Открыв ваш CSV файл, нажмите Ctrl+H,
затем произведите замену: \r\n
на: |


p.s.
Компонент TableGrid умеет делать экспорт CSV напрямую, где уже решена проблема с переносами строк

Form1.TableGrid1.SaveToTextFile('файл');
Dmitry.

Re: Импорт из csv

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

Re: Импорт из csv

Доброго дня всем. Дмитрий -   никак у меня не получается добиться результата, даже попытался на основе скрипта выложенного в посте 12 создать формы, и если все равно не работает. Может глянете хотя бы программу которую собрал согласно поста  -12. Что не так. Экспорт через грид в текстовый файл, при попытке импорта выводится например сообщение "обработано 13 строк", а в таблицы ничего не пишет.

Post's attachments

Attachment icon 456.zip 6.47 kb, 528 downloads since 2015-09-21 

Re: Импорт из csv

wertyby
Поправил

procedure Form1_Button2_OnClick (Sender: string; var Cancel: boolean);
var
   OpenDialog: TOpenDialog;
   sl: TStringList;
   arrStr: array of string;
   i,c: integer;
   counter: string;
   text: string;
   kategory: string;
   number: string;
begin
     OpenDialog := TOpenDialog.Create(Form1);
     if OpenDialog.Execute then
     begin
          sl := TStringList.Create;
          sl.LoadFromFile (OpenDialog.FileName);
          c := sl.Count - 1;

          for i := 0 to c do
          begin
                  arrStr:= SplitString(sl[i], ',');

                  // Пожелание
                  if  arrStr[0] <> '' then text := '''' + arrStr[0] + '''' else text := 'NULL';

                  // Категория
                  if  arrStr[1] <> '' then kategory := arrStr[1] else kategory := 'NULL';

                  // №
                  if  arrStr[2] <> '' then number := '''' + arrStr[2] + '''' else number := 'NULL';

                  // record_count
                  if  arrStr[3] <> '' then counter := arrStr[3] else counter := 'NULL';

                  SQLExecute ('INSERT INTO pozhelaniya (text, id_pozhelaniyakategoriya, textid, record_count) VALUES ('+ text +','+ kategory +','+ number +','+ counter +');');

                  Form1.Label19.Caption := 'Обработано '+ IntToStr(i)+ ' строк из ' + IntToStr(c);
                  Application.ProcessMessages;
          end;

          sl.Free;
          Form1.TableGrid3.dbUpdate;
          ShowMessage('Импорт завершен');
     end;
     OpenDialog.Free;
end;
Dmitry.

Re: Импорт из csv

Дмитрий спасибо, сверюсь. Вячеслав ещё помог, свой полёт прислал, путём разбора вроде тоже уже начал понимать где я тупил.

Re: Импорт из csv

Дмитрий,  в данном случае (исправленном Вами варианте), все вроде бы как и работает, но есть одно но - в случае выгрузки средствами базы в текстовый файл, используются междустрочные разделители вида "|", и при заливке в базу все так и заливается "т.е. привет|медвед|и|так|далее". Это нужно что то с файлом сделать?

Re: Импорт из csv

wertyby
в скрипте можете задать любой разделительный символ в данной строке:

arrStr:= SplitString(sl[i], ',');
Dmitry.

Re: Импорт из csv

Так разделитель столбцов используется ',' а разделитель '!' используется при экспорте для разделения строк в многострочном поле, и при импорте все заливается дословно - как есть в текстовом файле. Понимаю что туплю но как данный символ убрать при экспорте? Скрипт тогда должен по идее усложниться.