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

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

Вернуться   Форум программистов > .NET Frameworks (точка нет фреймворки) > C# (си шарп)
Регистрация

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

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

Ответ
 
Опции темы Поиск в этой теме
Старый 31.08.2017, 16:31   #1
Aleksandr H.
2 the Nation Glory
Старожил
 
Аватар для Aleksandr H.
 
Регистрация: 27.05.2014
Сообщений: 3,289
По умолчанию regex не делает то что хочу.

Метод тянет курс НБУ за параметром currency - USD, EUR, RUB
по ссылке
Возникает проблема с курсами для которых поле "Кількість одиниць" = 10. Ошибку дает в строке
Код:
var dAmount = Convert.ToInt32(Amount);
Цитата:
An exception of type 'System.FormatException' occurred in mscorlib.dll but was not handled in user code

Additional information: Входная строка имела неверный формат.
переменная matchAmount получается пустой.

Код:
public static string GetNBURate(string currency)
        {
            try
            {
                using (WebClient web = new WebClient())
                {
                    string lnk = "http://bank.gov.ua/control/uk/curmetal/currency/search?"+
                                @"formType=searchFormDate&time_step=daily&date=" + DateTime.Now.ToShortDateString() + 
                                @"&execute";
                    string html = web.DownloadString(lnk);
                    string pat = @"<tr>\s{1,}<td[^>]*>(.+?)</td>\s{1,}" +
                        @"<td[^>]*>"+currency.ToUpper()+@"</td>\s{1,}" +
                     @"(?<Amount><td[^>]*>([0-9]+)</td>\s{1,})" +
                     @"(?<Currency><td[^>]*>(.+?)</td>\s{1,})" +
                     @"(?<Price><td[^>]*>([0-9\.]+)</td>)";
                    
                    Regex regex = new Regex(pat);
                    Match match = regex.Match(html);
                    while(match.Success)
                    {
                        string Price = match.Groups["Price"].ToString();
                        string Amount = match.Groups["Amount"].ToString();
                        
                        Regex regexPrice = new Regex(@"\d+.\d+");
                        Match matchPrice = regexPrice.Match(Price);
                        var dPrice = Convert.ToDecimal(matchPrice.ToString(), new CultureInfo("en-US"));

                        Regex regexAmount = new Regex(@"\d+");
                        Match matchAmount = regexPrice.Match(Amount);
                        Amount = matchAmount.ToString();
                        var dAmount = Convert.ToInt32(Amount); // ERROR HERE :(

                        double Answer = Math.Round(Convert.ToDouble(dPrice) / dAmount,4);
                        return "Станом на сьогодні курс НБУ для " + currency.ToUpper() + 
                                " становить " + Answer.ToString();
                    }
                }
            }
            catch (WebException ex)
            {
                HttpWebResponse httpResp = (HttpWebResponse)ex.Response;
                if (ex.Status == WebExceptionStatus.ProtocolError && httpResp.StatusCode == HttpStatusCode.NotFound)
                {
                    // PageNotFound
                }
                else throw;

            }
            return "Інформація щодо валюти " + currency.ToUpper() + " відсутня.";
        }
пробовал на сайте
http://regexstorm.net/tester
паттерн
Код:
\d+
для текста
Цитата:
<td class=\"cell_c\">10</td>\r\n
отрабатывает нормально.

Нужна подсказка.
Кто умер, но не забыт, тот бессмертен.
Лао-Цзы.
Aleksandr H. вне форума Ответить с цитированием
Старый 31.08.2017, 16:52   #2
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,229
По умолчанию

банальная опечатка?
Код:
Regex regexAmount = new Regex(@"\d+");
                        Match matchAmount = regexPrice.Match(Amount);
наверное, должно быть:
Код:
Match matchAmount = regexAmount.Match(Amount);
Serge_Bliznykov вне форума Ответить с цитированием
Старый 31.08.2017, 17:00   #3
Alex11223
Старожил
 
Аватар для Alex11223
 
Регистрация: 12.01.2011
Сообщений: 19,500
По умолчанию

Для курсов есть куча API, зачем так извращаться?
https://bank.gov.ua/control/en/publi...rt_id=25365630

Ну и если уж парсить HTML, то не регекспами, а HTML парсером. Например HtmlAgilityPack.
Ушел с форума, https://www.programmersforum.rocks, alex.pantec@gmail.com, https://github.com/AlexP11223
ЛС отключены Аларом.

Последний раз редактировалось Alex11223; 31.08.2017 в 17:03.
Alex11223 вне форума Ответить с цитированием
Старый 31.08.2017, 23:48   #4
Aleksandr H.
2 the Nation Glory
Старожил
 
Аватар для Aleksandr H.
 
Регистрация: 27.05.2014
Сообщений: 3,289
По умолчанию

Serge_Bliznykov, как всегда саппорт неоценим. досадная очепятка.


методом тыка вариантов в инете, получил такой вариант для результата JSONа из линка сообщения 3
Код:
public static string NBURateAPI(string currency)
        {
            string Answer = null;
            HttpWebResponse response = null;

            try
            {
                using (WebClient web = new WebClient())
                {
                    
                    DateTime dt = DateTime.Now;

                    string date = DateTime.Now.ToString("yyyyMMdd", System.Globalization.CultureInfo.GetCultureInfo("en-US"));
                    string link = @"https://bank.gov.ua/NBUStatService/v1/statdirectory/exchange?valcode=" + currency +
                            @"&date=" + date + "&json";
                    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(link);

                    request.Method = "GET";
                    request.Accept = "application/json";


                    response = (HttpWebResponse)request.GetResponse();
                    StreamReader reader = new StreamReader(response.GetResponseStream());
                    String output = reader.ReadToEnd();
                    if (output != "[]")
                    {
                        var examples = Newtonsoft.Json.JsonConvert.DeserializeObject<Response[]>(output);
                        
                        Answer = "Станом на сьогодні курс "+examples[0].cc+" ("+examples[0].txt+") становить "+examples[0].rate;
                    }
                    else
                        Answer = "Інформація щодо валюти " + currency.ToUpper() + " відсутня.";
                }
            }
            catch (WebException ex)
            {
                HttpWebResponse httpResp = (HttpWebResponse)ex.Response;
                if (ex.Status == WebExceptionStatus.ProtocolError && httpResp.StatusCode == HttpStatusCode.NotFound)
                {
                    // PageNotFound
                }
                else throw;

            }
            finally
            {
                if (response != null)
                {
                    response.Close();
                }
                
            }
            return Answer;
        }


        public class Response
        {
            [JsonProperty("r030")]
            public int r030 { get; set; }
            [JsonProperty("txt")]
            public string txt { get; set; }
            [JsonProperty("rate")]
            public double rate { get; set; }
            [JsonProperty("cc")]
            public string cc { get; set; }
            [JsonProperty("exchangedate")]
            public string exchangedate { get; set; }
        }
Alex11223, а не могли бы вы на досуге накидать пример для HtmlAgilityPack конкретно для парсинга и поиска данных на странице по ссылки из сообщения 1? Чтобы делало то же, что и regex.
Кто умер, но не забыт, тот бессмертен.
Лао-Цзы.
Aleksandr H. вне форума Ответить с цитированием
Старый 01.09.2017, 08:13   #5
pu4koff
Старожил
 
Аватар для pu4koff
 
Регистрация: 22.05.2007
Сообщений: 9,065
По умолчанию

Код:
public string GetNBURate(string currency)
        {
            var web = new HtmlAgilityPack.HtmlWeb();
            var doc = web.Load(@"http://bank.gov.ua/control/uk/curmetal/currency/search?formType=searchFormDate&time_step=daily&date=31.08.2017&execute");
            var row = doc.DocumentNode.SelectSingleNode($"//table[4]//tr/td[text()=\"{currency.ToUpper()}\"]/../.");
            var amountNode = row?.SelectSingleNode(@"td[3]");
            var priceNode = row?.SelectSingleNode(@"td[5]");

            if (row != null && amountNode != null && priceNode != null &&
                decimal.TryParse(priceNode.InnerText, NumberStyles.AllowDecimalPoint, System.Globalization.CultureInfo.InvariantCulture, out var dPrice)
                && int.TryParse(amountNode.InnerText, out var dAmount))
            {
                return $"Станом на сьогодні курс НБУ для {currency.ToUpper()} становить {Math.Round(Convert.ToDouble(dPrice) / dAmount, 4)}";
            }

            return "Інформація щодо валюти " + currency.ToUpper() + " відсутня.";
        }
скачивать можно и WebClient'ом и грузить строку в HtmlDocument. XPath можно другие написать
pu4koff вне форума Ответить с цитированием
Старый 01.09.2017, 16:16   #6
Aleksandr H.
2 the Nation Glory
Старожил
 
Аватар для Aleksandr H.
 
Регистрация: 27.05.2014
Сообщений: 3,289
По умолчанию

Сложно И внятных примеров НАР с комментариями на русском не могу найти.
Кто умер, но не забыт, тот бессмертен.
Лао-Цзы.
Aleksandr H. вне форума Ответить с цитированием
Старый 01.09.2017, 16:31   #7
Alex11223
Старожил
 
Аватар для Alex11223
 
Регистрация: 12.01.2011
Сообщений: 19,500
По умолчанию

Это просто XPath, не нужны примеры по HAP. По сути там из важного только метод SelectNodes (или SelectSingleNode), который принимает XPath выражение и возвращает HTML элементы.

?. и $"{....}" это фичи C# с VS 2015 если что.

Ну а без английского программировать вообще сложно.
Ушел с форума, https://www.programmersforum.rocks, alex.pantec@gmail.com, https://github.com/AlexP11223
ЛС отключены Аларом.
Alex11223 вне форума Ответить с цитированием
Старый 03.09.2017, 11:11   #8
Aleksandr H.
2 the Nation Glory
Старожил
 
Аватар для Aleksandr H.
 
Регистрация: 27.05.2014
Сообщений: 3,289
По умолчанию

Посоветуете ресурс для обучения написания ХPath?
Кто умер, но не забыт, тот бессмертен.
Лао-Цзы.
Aleksandr H. вне форума Ответить с цитированием
Старый 03.09.2017, 11:38   #9
Alex11223
Старожил
 
Аватар для Alex11223
 
Регистрация: 12.01.2011
Сообщений: 19,500
По умолчанию

Я просто посмотрел несколько примеров на w3schools или типа того, а потом гуглил по необходимости (например "xpath attribute contains").

там же не так много часто используемых вещей
имя элемента, атрибуты в [ ], parent/child, наличие или отсутствие //

Например
Код:
//div[@id='myId']/span[contains(@class, 'myClass') and @data-attr]
Код:
<div id="myId">
    <span>hello</span>
    <span class="myClass notMyClass" data-attr="whatever" data-attr2="whatever2">world</span>
    <span class="myClass">!</span>
</div>
найдет второй span тут, в любом месте документа.

Если без //, то искать от текущего элемента, как td в примере выше.

/.. для перехода к родителю (как в файловой системе), например чтоб получить тут div
Код:
//span[contains(@class, 'myClass') and @data-attr]/..
Для быстрой проверки выражения можно использовать $x() в Хроме.

1.html - Google Chrome 2017-09-03 11.52.44.png
Ушел с форума, https://www.programmersforum.rocks, alex.pantec@gmail.com, https://github.com/AlexP11223
ЛС отключены Аларом.

Последний раз редактировалось Alex11223; 03.09.2017 в 11:55.
Alex11223 вне форума Ответить с цитированием
Старый 03.09.2017, 12:26   #10
Aleksandr H.
2 the Nation Glory
Старожил
 
Аватар для Aleksandr H.
 
Регистрация: 27.05.2014
Сообщений: 3,289
По умолчанию

Глупый вопрос "что почитать". Берешь и читаешь одно другое третье и что-то прояснится.

А лучше спросить конкретные вопросы что где непонятно

В этой строке, как объяснить для себя?
Код:
var row = doc.DocumentNode.SelectSingleNode($"//table[4]//tr/td[text()=\"{currency.ToUpper()}\"]/../.");
В row записываем все ноды по критерию:
а) из 4-й таблицы table, (//table[4])
б) найти все теги tr, (//tr)
в) в которых есть дети td c текстом <currency>, (/td[text()=\"{currency.ToUpper()}\"])
г) взять всех ихних детей (/..)
д) ??? (/.)

Почему 4-ая table если через просмотр кода, она 6-ая
att.jpg


Код:
var amountNode = row?.SelectSingleNode(@"td[3]");
var priceNode = row?.SelectSingleNode(@"td[5]");
в amountNode передаем текст из 3-го тега td?
в priceNode передаем текст из 5-го тега td?
@ значит "взять текст"?
row? - это что?
Кто умер, но не забыт, тот бессмертен.
Лао-Цзы.
Aleksandr H. вне форума Ответить с цитированием
Ответ


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



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Что делает this? Мой повелитель Общие вопросы по Java, Java SE, Kotlin 3 12.06.2016 11:21
Что это ? Что и как делает этот код? Dimka-novitsek Общие вопросы C/C++ 1 03.05.2015 01:57
что делает while(3) Sterben Помощь студентам 2 09.04.2015 23:54
Обьясните пожалуста как и что делает эта программа и почему она это делает. Dimka-novitsek Общие вопросы C/C++ 7 16.10.2013 12:02
Печать. Что делает MS и не делает Delphi Влад12 Общие вопросы Delphi 8 05.05.2010 20:04