Выбор нужного текста

293
20 июля 2018, 19:30

Не могу решить одну задачу

Есть текст: ...

Время 01:45 Страна JPY Факт.Базовые заказы в машиностроении (г/г) (апр) Прогноз 9,6% Пред. 3,9% Факт -2,4% Время 02:50 Страна JPY Факт.Базовые заказы в машиностроении (м/м) (апр) Прогноз 10,1% Пред. 2,8% Факт -3,9% Время 02:50 Страна JPY Факт.Денежный агрегат М2 (г/г) Прогноз 3,2% Пред. 3,3% Факт 3,2% Время 02:50 Страна GBP Факт.Индекс GBP/USD Прогноз 57,3% Пред.   Факт 57,1% Время 08:30 Страна USD Факт.Индекс золота Прогноз 64,2% Пред.   Факт 68,5% Время 08:30 Страна USD Факт.Индекс S&P 500 Прогноз 68,1% Пред.   Факт 55,5%

...

Перебираю текст построчно:

            String[] s = textBox1.Text.Split(new String[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
        int w = Convert.ToInt32(col_vo);
        for (int i = 0; i < w; i++)
        {
            label3.Text += s[i] + "\r\n";
        }

И вот в чем я не могу разобраться. Как в цикле выбирать например: В строчке Время 01:45 Страна JPY Факт.Базовые заказы в машиностроении (г/г) (апр) Прогноз 9,6% Пред. 3,9% Факт -2,4%

Только: 1:45 JPY Базовые заказы в машиностроении (г/г) (апр)

Если бы текст был статичным было бы проще, но он всегда меняется. Мысли есть, что можно по слову Время, найти время. Но не хватает знаний.
Подскажите какой метод использовать ?

Добавляю исходный файл: Яндекс Диск

Answer 1

Все началось, как я понял, с этого вопроса: Индекс за пределами диапазона C# XPath. Потом продолжилось здесь, а результатом должен был быть банальный парсинг сайта. Проблема эта не нова. Если поискать по SO, то можно найти кучу вопросов и ответов.

Только ради того, чтоб закончить эпопею с этим сайтом, решил помочь. Таблица на этом сайте строится динамически с помощью javascript. Потому либо нужено использовать что-то типа Selenium, либо, если не охота париться, просто открываем сайт в браузере, а потом сохраняем страницу в файл html. А дальше работаем с файлом

Создадим пару классов для хранения этой информации

public class EconomicCalendar
{
    public string Title { get; set; }
    public List<CalendarRow> Rows { get; } = new List<CalendarRow>();
}
public class CalendarRow
{
    public string ID { get; set; }
    public string EventAttrId { get; set; }
    public string DataEventDatetime { get; set; }
    public string FirstLeftTile { get; set; }
    public string CountryAbbr { get; set; }
    public string CountryRus { get; set; }
    public string CountryEng { get; set; }
    public string Forecast { get; set; }
    public string Previous { get; set; }
    public string Alert { get; set; }
    public string Volatility { get; set; }
}

Чтобы преобразовать HTML в XML установим такую библ.

Напишем такой подсобный класс

public class HtmlToXmlService
{
    /// <summary>
    /// Получение экземпляра XDocument на основе html файла
    /// </summary>
    /// <param name="pathToFile">путь к файлу html</param>
    /// <returns>экземпляр XDocument</returns>
    public static XDocument GetXDocument(string pathToFile)
    {
        if (String.IsNullOrEmpty(pathToFile)) throw new ArgumentNullException(nameof(pathToFile));
        if (!File.Exists(pathToFile)) throw new ArgumentException("Файл не найден!");
        //читаем файл и получаем документ
        XDocument result = null;
        using (StreamReader sr = File.OpenText(pathToFile))
        {
            result = FromHtml(sr);
        }
        //удаление пространства имен
        RemoveNamespaces(result);
        return result;
    }
    private static void RemoveNamespaces(XDocument result)
    {
        //удаление namespaces у элементов
        result.Descendants()
              .Attributes()
              .Where(x => x.IsNamespaceDeclaration)
              .Remove();
        foreach (var elem in result.Descendants())
            elem.Name = elem.Name.LocalName;
        //удаление namespaces у атрибутов элементов
        foreach (var attr in result.Descendants().Attributes())
        {
            var elem = attr.Parent;
            attr.Remove();
            elem.Add(new XAttribute(attr.Name.LocalName, attr.Value));
        }
    }
    private static XDocument FromHtml(TextReader reader)
    {
        // setup SgmlReader
        SgmlReader sgmlReader = new SgmlReader();
        sgmlReader.DocType = "HTML";
        sgmlReader.WhitespaceHandling = WhitespaceHandling.All;
        sgmlReader.CaseFolding = CaseFolding.ToLower;
        sgmlReader.InputStream = reader;
        return XDocument.Load(sgmlReader);
    }
}

В этом классе будем парсить xml с помощью LINQ (может не самым удобным образом..., критика приветствуется)

/// <summary>
/// Обработка страницы сайта полученной с адреса https://ru.investing.com/economic-calendar/
/// </summary>
public class EconomicCalendarService
{
    /// <summary>
    /// Парсинг файла HTML сохраненной страницы
    /// </summary>
    /// <param name="pathToHtmlFile">путь к файлу html</param>
    /// <returns>экземпляр EconomicCalendar </returns>
    public static Task<EconomicCalendar> GetEconomicCalendar(string pathToHtmlFile)
    {
        if (String.IsNullOrEmpty(pathToHtmlFile)) throw new ArgumentNullException(nameof(pathToHtmlFile));
        EconomicCalendar result = new EconomicCalendar();
        //получаем из Html файла -> XDocument
        XDocument document = HtmlToXmlService.GetXDocument(pathToHtmlFile);
        //название таблицы
        result.Title = document.Descendants("table")
                        .Where(table => table.Attributes("id").Any())
                        .Where(t => t.Attribute("id").Value.StartsWith("economicCalendarData"))
                        .Descendants("td")
                        .Where(td => td.Attributes("class").Any())
                        .Where(td => td.Attribute("class").Value.StartsWith("theDay"))
                        .First().Value;
        //извлекаем строки таблицы
        var crs = document.Root.Element("body")
                       .Descendants("tr")
                       .Where(tr => tr.Attributes("class").Any())
                       .Where(tr => tr.Attribute("class").Value.StartsWith("js-event-item"))
                       .Select(tr => new CalendarRow
                       {
                           ID = tr.Attribute("id")?.Value,
                           EventAttrId = tr.Attribute("event_attr_id")?.Value,
                           DataEventDatetime = tr.Attribute("data-event-datetime")?.Value,
                           FirstLeftTile = tr.Descendants("td")
                                   .FirstOrDefault(td => td.Attribute("class").Value.StartsWith("first left"))
                                   ?.Value,
                           CountryAbbr = tr.Descendants("td")
                                   .FirstOrDefault(td => td.Attribute("class").Value.StartsWith("left flagCur"))
                                   ?.Value,
                           CountryRus = tr.Descendants("td")
                                   .Where(td => td.Attribute("class").Value.StartsWith("left flagCur"))
                                   .Select(td => td?.Descendants().First()?.Attribute("title")?.Value)
                                   .FirstOrDefault(),
                           CountryEng = tr.Descendants("td")
                                   .Where(td => td.Attribute("class").Value.StartsWith("left flagCur"))
                                   .Select(td => td?.Descendants().First()?.Attribute("data-img_key")?.Value)
                                   .FirstOrDefault(),
                           Forecast = tr.Descendants("td")
                                   .FirstOrDefault(td => td.Attribute("class").Value.StartsWith("fore"))
                                   ?.Value,
                           Previous = tr.Descendants("td")
                                   .Where(td => td.Attribute("class").Value.StartsWith("prev"))
                                   .Select(td => td?.Descendants().First()?.Value)
                                   .FirstOrDefault(),
                           Alert = tr.Descendants("td")
                                   .Where(td => td.Attribute("class").Value.StartsWith("alert"))
                                   .Select(td => td.Attribute("data-name")?.Value)
                                   .FirstOrDefault(),
                           Volatility = tr.Descendants("td")
                                   .Where(td => td.Attribute("class").Value.StartsWith("left textNum"))
                                   .Select(td => td.Attribute("title")?.Value)
                                   .FirstOrDefault(),
                       });
        //вносим строки
        result.Rows.AddRange(crs);
        return Task.FromResult(result);
    }
}

Как-то так. Построение граф интерфейса банально, код приводить не буду. Только как пользоваться написанным выше классом

try
{
    EconomicCalendar calendar = await EconomicCalendarService.GetEconomicCalendar(File);
    Title = calendar.Title;
    Rows = calendar.Rows;
}
catch (Exception ex)
{
    _mainWindow.ShowMessage($"Возникла ошибка: {ex.Message}");
}

Пример можно скачать здесь

READ ALSO
Из String [ ] в byte[ ] - C#

Из String [ ] в byte[ ] - C#

Всем привет! Опишу суть проблемы есть массив string в который записаны адреса байтов по типу:

275
Как в C# WPF ListView динамически добавить картинку?

Как в C# WPF ListView динамически добавить картинку?

Имеется ListView, как отобразить картинки (bmp) и название файла, из любой выбранной папки

327
Не добавляется элемент в XML

Не добавляется элемент в XML

Не добавляется элемент в XML-базуПробую так:

248
Игральные карты — пасьянс

Игральные карты — пасьянс

Пишу консольную программку на c#, задание такое: Создать класс колоду картСоздать конструкторы колоды должны инициализировать колоду как...

337