Проблема с разделителем в csv через FileOpen

 

Пытаюсь научить советника читать новости. На удивление, даже почти получается. За исключением одной маленькой детали, которая встречается редко, но когда встречается, портит всю систему на остаток недели.

Новости беру с dailyfx.com в csv (например: http://www.dailyfx.com/files/Calendar-12-02-2012.csv), разделитель там запятая. Но она же изредка встречается в тексте описания новости, при этом весь кусок заключается в кавычки. Вот пара примеров: 

//такая нормально обрабатывается
Thu Jan 17,23:50,GMT,jpy,JPY Foreign Buying Japan Stocks (Yen),Low,¥233.8B,,¥178.9B  

//эта - уже не очень, но с ней можно справиться через StringReplace(Fix,", ","; ");
Thu Jan 17,09:30,GMT,eur,"EUR Spain to Sell 2015, 2018, 2041 Bonds",Medium,,,

//а вот эта вообще ломает все и не фиксится через StringReplace без порчи остальных разделителей
Wed Dec 5,09:30,GMT,eur,"EUR Spain to Sell 3,7; and 10-Year Bonds",Medium,,,

Кое-как второй случай удалось профиксить вот таким "костылем":

bool FixNews(string File) {
   string Fix;
   int handle = FileOpen(File,FILE_READ|FILE_CSV|FILE_UNICODE,0);
   int handle_fix = FileOpen(File+"-fix.csv",FILE_WRITE|FILE_CSV|FILE_UNICODE,",");
   if (handle == INVALID_HANDLE) Print("Не удалось открыть файл для исправления.");
   if (handle_fix == INVALID_HANDLE) Print("Не удалось создать временный файл для исправления.");
   
   while(!FileIsEnding(handle)){
      Fix = FileReadString(handle);
      StringReplace(Fix,", ","; ");
      FileWrite(handle_fix,Fix);
   }
   
   FileClose(handle);
   FileClose(handle_fix);
   
   if (!FileMove(File+"-fix.csv",0,File,FILE_REWRITE)) {
      Print("Не удалось переместить профиксеный файл.");
      return(false);
   }
   return(true);
}

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

Может, есть какой-то простой встроенный способ, а я о нем банально не знаю? Вот, к примеру, OpenOffice Calc совершенно не напрягают закавыченные запятые - он их правильно отправляет в одну колонку, при этом убирая лишние кавычки. Можно ли FileOpen как-то обучить такому? Или на худой конец как-то поправить костыль, чтобы отлавливал запятые внутри кавычек (и игнорировал при этом кавычки внутри других кавычек)? Была мысль про регулярные выражения, но я честно говоря даже не представляю, как к ним подойти в mql5.

 

Структура новостей постоянная? По вашим примерам выходит, что так.

Новостная строка состоит из 9 значимых полей, значит запятых разделителей 8.

В таком случае первое очевидное решение разделить строку по разделителю - ",".

Первые 4 и последние 4 куска будут данные, все остальное сама новость.

#property script_show_inputs
//--- input parameters
input string   NewsString;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   datanews News;
   newsParsing(NewsString,News);
   PrintFormat("Date=%s, time=%s, GMT=%s, Symbol=%s, News=%s, Val1=%s, Val2=%s, Val3=%s, Val4=%s",
                News.date,News.time,News.gmt,News.symb,News.news,News.val1,News.val2,News.val3,News.val4);
  }
//+------------------------------------------------------------------+
struct datanews
  {
   string            date;
   string            time;
   string            gmt;
   string            symb;
   string            news;
   string            val1;
   string            val2;
   string            val3;
   string            val4;
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void newsParsing(string str_news,datanews &strc_news)
  {
   ushort _sep=StringGetCharacter(",",0);
   string news_arr[];
   int nstring=StringSplit(str_news,_sep,news_arr);
   strc_news.date=news_arr[0];
   strc_news.time=news_arr[1];
   strc_news.gmt=news_arr[2];
   strc_news.symb=news_arr[3];
   strc_news.val1=news_arr[nstring-4];
   strc_news.val2=news_arr[nstring-3];
   strc_news.val3=news_arr[nstring-2];
   strc_news.val4=news_arr[nstring-1];
   for(int i=4; i<nstring-4;i++) strc_news.news+=news_arr[i]+",";
   int lennews=StringLen(strc_news.news);
   StringSetCharacter(strc_news.news,lennews-1,"");
  }
//+------------------------------------------------------------------+

  Вот ваши примеры:

Date=Thu Jan 17, time=23:50, GMT=GMT, Symbol=jpy, News=JPY Foreign Buying Japan Stocks (Yen), Val1=Low, Val2=¥233.8B, Val3=(null), Val4=¥178.9B  
Date=Thu Jan 17, time=09:30, GMT=GMT, Symbol=eur, News="EUR Spain to Sell 2015, 2018, 2041 Bonds", Val1=Medium, Val2=(null), Val3=(null), Val4= 
Date=Wed Dec 5, time=09:30, GMT=GMT, Symbol=eur, News="EUR Spain to Sell 3,7; and 10-Year Bonds", Val1=Medium, Val2=(null), Val3=(null), Val4= 

 Если структура новостной строки не постоянная то придется парсить строку "вручную", учитывая во внимание кавычки.

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

 

Мы подумаем.

Действительно, при чтении строки из csv-файла надо бы учитывать ограничивающие строку кавычки. В этом месте - много нюансов, надо думать

 
stringo:

Мы подумаем.

Действительно, при чтении строки из csv-файла надо бы учитывать ограничивающие строку кавычки. В этом месте - много нюансов, надо думать

А ничего там думать не нужно, это дело программиста пишущего парсер.

Незачем из за этого коверкать язык.

Конкретно по http://www.dailyfx.com/files/Calendar-12-02-2012.csv читаете строку как есть, удаляете символы переноса, парсите строку по разделителю кавычки, после этого имеете три отдельных поля для парсинга по разделителю ";" и всё идёт как надо.

 
kPVT:

Структура новостей постоянная? По вашим примерам выходит, что так.

Новостная строка состоит из 9 значимых полей, значит запятых разделителей 8.

В таком случае первое очевидное решение разделить строку по разделителю - ",".

Первые 4 и последние 4 куска будут данные, все остальное сама новость.

  Вот ваши примеры:

 Если структура новостной строки не постоянная то придется парсить строку "вручную", учитывая во внимание кавычки.

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

Круто, большое спасибо :) Попытаюсь теперь адаптировать это дело непосредственно в парсер новости, чтобы обойтись без лишней перезаписи файла...

 
stringo:

Мы подумаем.

Действительно, при чтении строки из csv-файла надо бы учитывать ограничивающие строку кавычки. В этом месте - много нюансов, надо думать

Благодарю за внимание к теме! Конечно, встроенное решение было бы удобнее. Но понимаю, что такую задачу решить достаточно стабильно и универсально было бы не просто.
 
Urain:

А ничего там думать не нужно, это дело программиста пишущего парсер.

Незачем из за этого коверкать язык.

Конкретно по http://www.dailyfx.com/files/Calendar-12-02-2012.csv читаете строку как есть, удаляете символы переноса, парсите строку по разделителю кавычки, после этого имеете три отдельных поля для парсинга по разделителю ";" и всё идёт как надо.

Взять кавычки за разделитель там, где они встречаются хоть раз и именно ее исправлять - такая идея у меня тоже была... Но в этом случае все упирается в куда более часто встречающиеся в тексте новостей серии из 4+ кавычек - т.е. "если новость сама по себе "закавычена" число " внутри может разниться"... Но вероятно это я просто еще слишком чайник в программировании, чтобы сообразить, как правильно эту тему разрулить. ^^
 
Lone_Irbis:
 ... все упирается в куда более часто встречающиеся в тексте новостей серии из 4+ кавычек...

Именно про это я говорил: "много нюансов".

 
stringo:

Именно про это я говорил: "много нюансов".

Слава, а есть ли в планах развивать календарь в терминале? Было бы здорово, чтобы была у Вас на сервере максимально глубокая история новостных событий, которую можно читать программно и тестировать.
 
tol64:
Слава, а есть ли в планах развивать календарь в терминале? Было бы здорово, чтобы была у Вас на сервере максимально глубокая история новостных событий, которую можно читать программно и тестировать.
В планах есть. Мы про это уже говорили. Точных сроков назвать не могу - не знаю.
 
stringo:
В планах есть. Мы про это уже говорили. Точных сроков назвать не могу - не знаю.

Пропустил значит это обсуждение. Значит пока сами будем справляться. Но сам факт того, что это есть в планах, радует конечно. ) 

Причина обращения: