Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Скриптовые языки программирования > PHP
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 26.10.2012, 17:04   #1
Meta2
Пользователь
 
Регистрация: 28.10.2009
Сообщений: 38
По умолчанию Разработка регулярного выражения для разбора строки с разделителями

Всем доброго дня!

Есть у меня задачка - загрузить в некую БД сведения из файлов формата XLS. Загрузка осуществляется программой, которая извлекает данные из файла XLS, при помощи COM-объекта Excel. Как следствие, данные выгружаются крайне долго и печально, а учитывая что файлов около десятка и в каждом по 7000-10000 строк, то всё весьма не быстро.

Поэтому было решено использовать Excel для превращения файла XLS в CSV, а потом обработка CSV как массива строк. Строки предполагалось разбирать при помощи регулярного выражения, используя встроенный в Windows процессор регулярных выражений VBScript.RegExp.

По умолчанию (и в соответствии с настройками системы) в качестве разделителя Excel использует точку с запятой. Всё было бы хорошо, пока в файлах не стали попадаться значения такого вида: 123;456;7";"89
Очевидно, что Excel экранирует символ-разделитель, обрамляя его кавычками. И это бы ничего, но в файлах встречаются значения и такого вида: 123;456;"122";"789; ... то есть полная мешанина из кавычек и символов-разделителей.

Проблема состоит в том, как быстро и просто разобрать такой файл по отдельным значениям. Excel с такой задачей справляется великолепно.

У меня родилось несколько идей, как это сделать:
  1. Нормализовать файл;
  2. Использовать регулярное выражение.

Под нормализацией файла я понимаю замену всех встреченных в файле символов-разделителей ( ; ) на какой-нибудь нейтральный символ, который потом легко заменит назад, например на символ "неразрывный пробел" (CHAR(160)).

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

Вариант плох тем, что надо делать предварительную обработку данных, потом использовать регулярное выражение, а потом производить обратную замену данных. Ввиду этих особенностей родился второй вариант - сразу написать регулярное выражение, разбирающее строку нужным образом. При реализации данного способа я столкнулся с той проблемой, что моих навыков создания регулярных выражений недостаточно для написания РВ, сразу корректно разбирающего строку, с учётом кавычек, наличия символов-разделителей в строке и т.п.

Я покопался в интернете и нашёл пару РВ, максимально близко решающих мою задачу:
  1. ,(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))
  2. (""([^""]*|""{2})*""(,|$))|""[^""]*""(,|$)|[^,]+(,|$)|(,)
Ввиду того, что парсер заменяет скобку с точкой с запятой на смайлик, точка с запятой заменена просто запятой

Первое регулярное выражение находит в строке все символы-разделители, отделяя те, которые экранированы кавычками:
123;456;7890 -> ( ; )(3)( ; )(7), где (3)(7) - позиции символа-разделителя.
123;456;78";"90 -> ( ; )(3)( ; )(7)
Строки, полученные

Второе выражение выделяет сразу элементы строки, но всё равно требуется пост-обработка - удаление символа-разделителя с концов извлеченных групп символов, и удаление парных кавычек по краям извлечённого текста. И да, второе выражение работает некорректно, например, на такой строке: 123;"456;""""";789
Выражение считает, что в строке 4 элемента, хотя данная строка была получена из 3 ячеек: 123 | 456;"" | 789

Собственно, прошу помощи в следующем:
  • Решал ли кто-нибудь аналогичную задачу и если да, то может быть знает более элегантный способ её решения?
  • Помогите оптимизировать какое-либо из существующих регулярных выражений, или помогите написать новое РВ, которое бы корректно отрабатывало на файлах CSV, продуцируемых Microsoft Excel 2010

Спасибо!
Meta2 вне форума Ответить с цитированием
Старый 26.10.2012, 19:31   #2
LZero
Форумчанин
 
Регистрация: 20.07.2012
Сообщений: 129
По умолчанию

Первый результат в гугле по запросу csv regex split
Код:
<?php
$delimiter = preg_quote(';');
$enclosure = preg_quote('"');
$msg = '1;24;"45;32";"456""99";qwerty;56,78';
$split = preg_split("/{$delimiter}(?!(?:[^{$enclosure}{$delimiter}]|[^{$enclosure}]{$delimiter}[^{$enclosure}])+{$enclosure})/", $msg);
print_r($split);
LZero вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Разработка регулярного выражения для извлечения артикулов товаров Meta2 Microsoft Office Excel 5 21.03.2012 21:02
Библиотечка для разбора формул kir_rik Общие вопросы C/C++ 2 29.11.2011 22:25
Корректность Регулярного выражения Altera Свободное общение 4 18.08.2011 17:44
У меня проблема с одной из моих функций для разбора строки, язык С/С++ [Федя] Общие вопросы C/C++ 3 07.01.2011 22:14
Нужна программа для грамматического разбора конструкции гипотетического языка программирования loshara_de_kontara Помощь студентам 0 10.12.2008 23:20