Практика регулярных выражений в 1С или "парсим неудобные форматы"




Принцип обмена данными из 1С с сайтом (на MySQL) и выдачи (публикации) этих данных по запросу.
PHP-Скрипт автоматической загрузки данных из файла данных в формате CSV в базу данных сайта работающего на WordPress.

В продолжение моей темы: 1С:Альфа-Авто Автосалон Автосервис: обмен с сайтом.
С помощью данного скрипта можно загружать в автоматическом режиме, по расписанию, данные сервисных книжек (ремонтов авто) из 1С:Альфа-Авто Автосалон Автосервис.
Также можно загружать данные в ручном режиме: для этого делается скрытая страница, где размещается специальная кнопка.
Комментарии размещенные внутри скрипта разъяснят логику и порядок действия.
Комментарии с "/////    echo" использовались для отладки.
Дополнительно создана таблица для журналирования результатов загрузки данных.
Скрипт включает в себя защиту от SQL инъекций (думаю безопасность соблюдена в полной мере).
В кратце:
1. Пишется скрипт, который запускает этот.
2. Создается регламентное задание в WordPress, по которому запускается скрипт из п.1. 
3. Этот скрипт осуществляет проверку на существование файла обмена в папке.
4. Если данные не новые, загрузка не производится.
5. Если данные новые, очищается таблица сервисных книжек.
6. Загружаются новые данные.

Собственно сам скрипт:

<?php // Полная загрузка сервисных книжек, создан 2024-01-05 12:44:55

global $wpdb2;
global $failure;
global $file_hist;

/////  echo '<H2><b>Старт загрузки</b></H2><br>';

$failure=FALSE;
//подключаемся к базе
$wpdb2 = include_once 'connection.php'; ; // подключаемся к MySQL
// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if (!empty($wpdb2->error))
{
/////   echo '<H2><b>Ошибка подключения к БД, завершение.</b></H2><br>';
$failure=TRUE;
wp_die( $wpdb2->error );
}

$m_size_file=0;
$m_mtime_file=0;
$m_comment='';
/////проверка существования файлов выгрузки из 1С
////файл выгрузки сервисных книжек
$file_hist = ABSPATH.'/_1c_alfa_exchange/AA_hist.csv';
if (!file_exists($file_hist))
{
/////   echo '<H2><b>Файл обмена с сервисными книжками не существует.</b></H2><br>';
$m_comment='Файл обмена с сервисными книжками не существует';
$failure=TRUE;
}

/////инициируем таблицу лога
/////если не существует файла то возврат и ничего не делаем
if ($failure){
///включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET['foo']
/////   echo '<H2><b>Попытка вставить запись в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>$m_comment));
wp_die();
/////    echo '<H2><b>Возврат в начало.</b></H2><br>';
return $failure;
}
/////проверка лога загрузки, что бы не загружать тоже самое
$masiv_data_file=stat($file_hist);   ////передаем в массив свойство файла
$m_size_file=$masiv_data_file[7];    ////получаем размер файла
$m_mtime_file=$masiv_data_file[9];   ////получаем дату модификации файла
////создаем запрос на получение последней удачной загрузки
////выбираем по штампу времени создания (редактирования) файла загрузки AA_hist.csv, $m_mtime_file

/////   echo '<H2><b>Размер файла: '.$m_size_file.'</b></H2><br>';
/////   echo '<H2><b>Штамп времени файла: '.$m_mtime_file.'</b></H2><br>';
/////   echo '<H2><b>Формирование запроса на выборку из лога</b></H2><br>';
////препарируем запрос
$text_zaprosa=$wpdb2->prepare("SELECT * FROM `vin_logs` WHERE `last_mtime_upload` = %s", $m_mtime_file);
$results=$wpdb2->get_results($text_zaprosa);

if ($results)
{   foreach ( $results as $r)
{
////если штамп времени и размер файла совпадают, возврат
if (($r->last_mtime_upload==$m_mtime_file) && ($r->last_size_upload==$m_size_file))
{////echo '<H2><b>Возврат в начало, т.к. найдена запись в логе.</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>'Загрузка отменена, новых данных нет, т.к. найдена запись в логе.'));
wp_die();
return $failure;
}
}
}
////если данные новые, пишем в лог запись о начале загрузки
/////echo '<H2><b>Попытка вставить запись о начале загрузки в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>0, 'last_size_upload'=>$m_size_file, 'comment'=>'Начало загрузки'));

////очищаем таблицу
$clear_tbl_zap=$wpdb2->prepare("TRUNCATE TABLE %s", 'vin_history');
$clear_tbl_zap_repl=str_replace("'","`",$clear_tbl_zap);
$results=$wpdb2->query($clear_tbl_zap_repl);
/////   echo '<H2><b>Очистка таблицы сервисных книжек</b></H2><br>';
if (empty($results))
{
/////   echo '<H2><b>Ошибка очистки таблицы книжек, завершение.</b></H2><br>';
//// если очистка не удалась, возврат
$failure=TRUE;
wp_die();
return $failure;
}

////загружаем данные
$table='vin_history';         // Имя таблицы для импорта
//$file_hist Имя CSV файла, откуда берется информация     // (путь от корня web-сервера)
$delim=';';          // Разделитель полей в CSV файле
$enclosed='"';      // Кавычки для содержимого полей
$escaped='\

32 Comments

  1. Арчибальд

    Совершенно мне не требуется. Но не могу не оценить «красоту игры» (© Ю. Ким)

    Reply
  2. cool.vlad4

    автор, молодец, но плюс я ставить не буду. В общем случае html не советуют парсить регулярными выражениями, очень часто будут ошибки. Приводят html к валидному xml, а дальше xpath или xslt, если хочется. В редких случаях, я допускаю использование рег.выражений для быстрого и за один раз — извлечения данных.

    Reply
  3. Armando

    Хочу чтоб регекспы сделали объектом языка 1С, тогда ваще кошерно было бы.

    РегулярноеВыражение = Новый РегулярноеВыражение;

    Reply
  4. 1cspecialist

    (2) Не совсем понял, чем вам поможет xpath или xslt в этом случае — при приведении html к валидному xml вы столкнетесь абсолютно с теми же вопросами, как и при парсинге html регулярными выражениями. Да и само утверждение «html не советуют парсить регулярными выражениями» весьма спорно — это все равно что сказать, что не рекомендуют автоматизировать «Газпром» на 1С. Почему нет? Нужно рассматривать каждую ситуацию в отдельности. Регулярные выражения — это такой же инструмент как и многие другие.

    Reply
  5. 1cspecialist

    (2) вообще, я да и многие другие были бы признательны, если бы вы написали тут статью про парсинг с помощью xpath, xslt и приведение html к валидному xml — просто уж очень тема интересная

    Reply
  6. cool.vlad4

    (4) я вроде ничего, такого не написал, даже похвалил вас. не нарывайтесь. Эти глупые сравнения не в счет, поскольку я нигде не писал, что от регулярных выражений надо отказыватся. А не советуют пользоватся для парсинга html вполне серьезные программисты из stackoverflow. Я куда больше доверяю, чем вам. xpath и xslt не тоже самое, не знаете, не говорите.

    Reply
  7. cool.vlad4

    (5) не обещаю, но может быть.

    Reply
  8. cool.vlad4

    +6 вот ссылки на те сайты http://www.codinghorror.com/blog/2009/

    Reply
  9. German

    (3) да и будет вам как «Внешние источники данных»

    (5) про Xpach тут можно пример посмотреть тут http://main.1c-ei.ru/Home/help/console/template/xml

    а парсинг HTML лучше доверить специализированным но очень редким уже(!) вещам, например http://blog.1c-ei.ru/2009/09/openkapow.html

    Reply
  10. cool.vlad4

    на самом деле просто писать статью, с целью обучения, конечно, благородно, но я не могу себя заставить. У меня идея и потихоньку я её реализовываю, сделать обычный прокси, через который, в зависимости от опций и можно будет получать/парсить/кэшировать/приводить в xml и т.д. — тогда можно будет и из 1С-ки это делать. Для знакомства с xpath — поставьте расширение для chrome/firefox (firepath например). Единственно, нужно помнить, что webkit-овские движки и mozilla, добавляют некоторые изменения — например <tbody>, в таблицы, которого нет. Поэтому xpath может быть неточным в браузере.

    Reply
  11. 1cspecialist

    (10) что такое xpath я представляю, реализация объекта для работы с xpath есть и в 1С, но у этой методики есть также и минус — для работы требуется построение DOM дерева, по которому xpath будет ходить, а это требует ресурсов оперативки, хотя наверное на мощных серверах это и не такой уж и большой минус

    то что вы кому-то доверяете, а кому-то нет — ваше право, но я хотел просто услышать, почему не рекомендуется использовать регулярные выражения, как решается проблема идентификации данных? был бы признателен, если бы вы тезисно изложили суть.

    Reply
  12. cool.vlad4

    (11) для этого надо либо прочесть ссылки, которые я дал выше, либо понять, что такое регулярное выражение(в статье об этом ни слово). html не относится к регулярным языкам. Есть такая теорема любой регулярный язык представим в виде регулярного выражения. html нет.

    Reply
  13. cool.vlad4

    (11) и почему есть DOM, если regexp так хорош? Сколько вы спарсили сайтов? Кто гарантирует вам, что если для пару страниц ваша регулярка сработает, то и для 1000 страниц тоже? Почему DOM сработает? да потому, что вы парсите те участки, которые занимают вполне определенное положение в дереве иначе смысла нет.И тем не менее я не исключаю регулярки, я использую и то, и то. Просто в статье посыл другой.

    Reply
  14. 1cspecialist

    (13) ну я так примерно и представлял, все равно спасибо за ответ

    Reply
  15. theologian

    нужная вещь. спасибо

    Reply
  16. curys

    хорошая штука, благодарю

    Reply
  17. byuf_in

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

    Reply
  18. Seregalink

    спасибо, хорошая штука!

    Reply
  19. opiumdx

    Спасибо!

    Reply
  20. CaSH_2004

    Думаю у любого инструмента есть минусы, но с непривычки легче пользоваться более простыми инструментами, а потом переходить к более сложным. Также важно знать какие минусы есть. Поэтому спасибо и автору и cool.vlad4 за критику (правда она какая-то злая, наверно столкнулся с этими проблемами сам 🙂

    Reply
  21. maljaev

    Прочитал пост 13, вот абсолютно соглашусь с его автором — использую и то и другое в определенных случаях, но сам RegExp не панацея, тем более относительно HTML (DOM лучше). Но в определенных ситуациях RegExp рулит.

    Reply
  22. 1cspecialist

    (21) regexp спасет в большинстве случаев, особенно когда нужно оптимизировать производительность в условиях ограниченных ресурсов. Попробуйте в браузере открыть файл html размером 200 мб (и это далеко не самый большой файл, который приходится парсить) и посмотрите в диспетчере задач windows — он сожрет у вас больше 2 гигабайт оперативной памяти на построение DOM-модели документа. Тоже самое будет и с любой другой программой, использующей DOM для своей работы. Если у вас на компьютере 4 Гб и/или 32-разрядная ось то легко получите out of memory. Т.е. предложенный вариант с xpath будет еле ворочиться, если вообще зашивелится.

    PS. Конечно xpath хороший и надежный выбор, но говорить, что regexp ненадежен — тоже нельзя. Еще раз повторюсь — нужно смотреть на условия конкретной задачи. В большинстве случаев regexp прекрасно справится с увесистыми файлами и причем не на самых мощных компьютерах. Если речь идет просто о парсинге сайтов, то конечно лучше использовать xpath, но с файлами с большим объемом лучше использовать механику последовательного чтения и парсинга, что собственно как нельзя лучше осуществляет regexp.

    Reply
  23. vikorn

    Нужная вещь, скопировал себе, спасибо

    Reply
  24. laeg

    Одно время, писал на 1с-ке парсер товаров с нескольких интернет магазинов

    тупое перебирание текста, поиск по тегам не есть гуд. Малейшие изменение в дизайне и все коту под хвост.

    Спасибо за статейку, при дальнейшей разработке, попробую использовать ваши наработки.

    Reply
  25. Minotavrik

    И не жалко тратить время на это? Во времена ассемблера и с статья была бы бесценна. В коде много других участков, которые надо думать как оптимизировать. А вот работа со строками в 1с вроде реализована и довольно не плохо.

    Но статья клевая снимаю шляпу за усердие.

    Reply
  26. dtitov

    Спасибо, очень вовремя.

    Reply
  27. petrovaUL

    нужная вещь. спасибо

    Reply
  28. ratinc

    Жаль что regexp у vbscript куцый.

    Никак не удастся развернуться в полную силу.

    Сильно не хватает следующего:

    No A or  anchors to match the start or end of the string. Use a caret or dollar instead.

    Lookbehind is not supported at all. Lookahead is fully supported.

    No atomic grouping or possessive quantifiers

    No Unicode support, except for matching single characters with

    No named capturing groups. Use numbered capturing groups instead.

    No mode modifiers to set matching options within the regular expression.

    No conditionals.

    No regular expression comments. Describe your regular expression with VBScript apostrophe comments instead, outside the regular expression string.

    Может можно ещё к чему com поиметь с «нормальным» regexp?

    Буду признателен за помощь в поиске альтернативы

    PS. Майкрософт как обычно реализует «свои» стандарты вот и regexp-у досталось 🙂

    Reply
  29. serpisal

    Хорошее решение, спасибо!

    Reply
  30. Veduin

    Интересно и познавательно! Спасибо!

    Reply
  31. ratinc

    Что то тема совсем заглохла. Оскудела земля русская программистами 🙂

    Ну неужели никто не подскажет откуда ещё кроме vbscript можно regexp поиметь?

    Reply
  32. EmpireSer

    (32) ratinc, от delphi. Они там его от каких-то С++ библиотек прикрутили.

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *