Скачать MetaTrader 5

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

Авторизуйтесь или зарегистрируйтесь, чтобы добавить комментарий
Нужно пополнить счет? Пополняй удобным тебе способом!
Lone_Irbis
261
Lone_Irbis 2013.09.03 18:32 

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

Новости беру с 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.

Pavel Tsatsenko
842
Pavel Tsatsenko 2013.09.04 05:02  

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

Новостная строка состоит из 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. Чтобы получить от скрипта правильный результат на второй и третьей новости из вашего примера, нужно после последней запятой добавить хоть пробел. При чтении из файла там видимо должны быть символы окончания строки и перевода каретки, так что вручную ничего добавлять не надо. 

Slawa
Модератор
6841
Slawa 2013.09.04 06:51  

Мы подумаем.

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

Nikolay Demko
12464
Nikolay Demko 2013.09.04 12:55  
stringo:

Мы подумаем.

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

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

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

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

Lone_Irbis
261
Lone_Irbis 2013.09.05 02:55  
kPVT:

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

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

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

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

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

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

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

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

Lone_Irbis
261
Lone_Irbis 2013.09.05 02:57  
stringo:

Мы подумаем.

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

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

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

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

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

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

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

Anatoli Kazharski
56910
Anatoli Kazharski 2013.09.05 07:53  
stringo:

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

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

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

12
Авторизуйтесь или зарегистрируйтесь, чтобы добавить комментарий