Страницы

Поиск по вопросам

четверг, 12 декабря 2019 г.

Получить реальное место возникновения ошибки

#c_sharp #net


Если я ловлю ошибку в методе, а затем в блоке catch делаю throw этой ошибки на верх,
то в стеке ошибок пишется именно, что ошибочной строкой является throw.

Можно ли как-то получить реальное место возникновения ошибки?

Пример кода:

 static void Main(string[] args)
    {
        try
        {
            var t = 1;
            var t3 = 2;
            var t4 = t - t3;
            throw new Exception("BlaBla bla");
        }
        catch (Exception ex)
        {
            throw;
        }
    }




Тут у меня пишется, что исключение возникло не в throw new Exception("BlaBla bla");
, а на строчке с throw;
    


Ответы

Ответ 1



Делайте throw; // перебросить с оригинальным стектрейсом А не throw ex; // бросить заново и потерять стектрейс К сожалению, если исключение было брошено, поймано, и переброшено в одном и том же методе - строчка в стектрейсе поменяется даже в случае если был использован throw;. CLR использует SEH, а тот использует стекфремы для отслеживания цепочки вызовов. На один метод - один стекфрейм, так что перебрасывание исключения в рамках одного метода перетирает оригинальный stack trace. Т.е. любой метод бросания исключения - и throw;, и throw ex; - изменяют стектрейс. Просто первый сохраняет более глубокие фреймы, а второй - нет. Вопрос на английском: enSO: Incorrect stacktrace by rethrow

Ответ 2



Это можно сделать на современном C#, хотя и не так изящно, как хотелось бы. Вам нужно поместить логику до throw в фильтр исключений, и вернуть из него false для случая, когда исключение нужно пробросить. При этом код вообще не будет заходить в catch. Вместо метода static void Main(string[] args) { var t = 1; try { var t3 = 2; var t4 = t - t3; throw new Exception("BlaBla bla"); } catch (Exception ex) { Console.WriteLine($"Exception with message {ex.Message} thrown, t = {t}"); throw; } } (тут в StackTrace только строка с throw) у вас получится вот такое: static void Main(string[] args) { var t = 1; try { var t3 = 2; var t4 = t - t3; throw new Exception("BlaBla bla"); } catch (Exception ex) when (Filter(ex)) { } bool Filter(Exception ex) { Console.WriteLine($"Exception with message {ex.Message} thrown, t = {t}"); return false; } } (в StackTrace только строка с throw new Exception("BlaBla bla");). Ещё один популярный (в узких кругах) вариант — использование System.Runtime.ExceptionServices.ExceptionDispatchInfo. Вот такой код: static void Main(string[] args) { var t = 1; try { var t3 = 2; var t4 = t - t3; throw new Exception("BlaBla bla"); } catch (Exception ex) { Console.WriteLine($"Exception with message {ex.Message} thrown, t = {t}"); ExceptionDispatchInfo.Capture(ex).Throw(); } } производит StackTrace из двух частей: at Test.Program.Main(String[] args) in ...\Program.cs:line 38 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at Test.Program.Main(String[] args) in ...\Program.cs:line 43 Строка 38 содержит throw new Exception("BlaBla bla");, а строка 43 — ExceptionDispatchInfo.Capture(ex).Throw();. (Я вынес переменную t, чтобы к ней можно было обращаться из блока catch ну или из локальной функции.) Ограничение метода: невозможно использовать async-метод в фильтре. При большом желании, фильтр можно и заинлайнить. Синтаксис при этом становится совсем вырвиглазным.

Ответ 3



Можно: try { ... } catch(ExceptionType ex) { throw; // а не throw ex; }

Проверка ссылки на изображение. Битая или нет

#jquery


Есть способ проверить  на наличие битой ссылки на изображение, а есть ли способ
проверить именно ссылку на изображение?

Проверка наличия изображения
    


Ответы

Ответ 1



Вообще все просто, создаем изображение и пытаемся загрузить его. Если получилось - ссылка есть, если не получилось, то вероятнее ссылки нет ( либо проблемы на сервере ) const checkImgSrc = src => { const img = new Image(); img.onload = function () { console.log(`valid src: ${src}`); } img.onerror = function () { console.log(`unvalid src: ${src}`); } img.src = src; } checkImgSrc('eruiqnwg'); // возможно ссылка уже устареет, но все же checkImgSrc('https://fullhdpictures.com/wp-content/uploads/2015/03/Snow-Leopard-Full-HD-Wallpapers.jpg');

Ответ 2



С помощью jQuery $('#myImage').on('error', function () { $(this).attr('src', 'path_to_default_image.png'); }); Нативный JS var image = document.getElementByID('myImage'); image.onload = function () { console.log('Done'); }; image.onerror = function () { image.src = 'path_to_default_image.png'; };

Ответ 3



В JQuery можно проверить ссылку на изображение с помощью функции $.ajax. Единственное условие: URL изображения и URL сайта должны иметь один и тот же протокол (т. е. HTTP только с HTTP, а HTTPS только с HTTPS). По крайней мере, так в Google Chrome. Это сделано для безопасности клиента. Подробнее см. https://ru.wikipedia.org/wiki/Правило_ограничения_домена и https://learn.javascript.ru/same-origin-policy. Код: https://jsfiddle.net/0cjh96st/95/ $("#check-it").click (function () { $("#img-container").append('

Wait...

'); $.ajax($("#url").val()) .done(function(jqXHR) { $("#img-container").append(''); }) .fail(function(jqXHR) { $("#img-container").append('

Can\'t open URL: '+$("#url").val()+'

status: '+jqXHR.status+'

'); }) .always (function () { $(".wait").remove(); }); }); .label { display: inline-block; padding: 6px; } #img-container { display: flex; flex-wrap: wrap; } #img-container>* { display: inline-block; min-width: 100px; height: 100px; border: 3px solid #feb; margin: 3px; padding: 3px; } #img-container>.ok { border-color: #bef; } .wURL { font-weight: bold; color: #febfeb; } #url { width: 300px; }

URL of image:



Переход на с# под веб: классический asp или core?

#c_sharp #aspnet_mvc #aspnet_core


Решил перейти с PHP на C# для работы под веб. Как я понял, есть 2 актуальных фрейморка,
для перехода: .NET MVC5 и .NET Core 2.

Так вот вопрос, расскажите пожалуйста, с чего будет лучше начинать, какие преимущества
у данной технологии, отличия и т.п. Мне нужен будет, для написание высоконагруженного
проекта в дальнейшем.

Заранее спасибо за помощь.
    


Ответы

Ответ 1



Нужно понимать, что .NET Core != ASP.NET Core. .NET Core - это кросплатформенный фреймворк. Для разработки различных видов приложений, от консолек до микросервисов ASP.NET Core - это фреймворк для разработки Web-приложений, который может работать как на .NET Core, так и на обычном .NET Framework. Core в названии - это просто странный маркетинговый трюк. Вот так выглядит wizard создания проекта ASP.NET Core, если вызывать его из поддерева Web, а не из поддерева Core. Вы можете вполне выбрать полный .NET Framework. По сравнению с ASP.NET MVC 5, ASP.NET Core - это просто следующая версия. ASP.NET MVC 5 вышел в 2013-ом году. После этого он был значительно переработан, получил поддержку .NET Core, и следующая его версия была выпущена под именем ASP.NET Core. Это просто особенность нумерации версий ASP.NET - 1, 2, 3, 4, (5), Core 1, Core 2. Так что ваш вопрос на самом деле сводится к "учить версию 5 пятилетней давности или учить последнюю версию 5 + 2". Ответ, на мой взгляд, очевиден :)

Ответ 2



В октябре 2018 заканчивается срок техподдержки asp.net core 2.0 поэтому пишите сразу на asp.net core 2.1 -- технология эта уже давно зрелая, можно использовать в продакшене. В её же достоинствах - мультиплатформенность, сможете запускать не только на IIS под windows, но и на линкс-платформах, где-нибудь в облаке. Я вот пишу код и тестирую на windows 10 -- но продакшн у меня на линуксе. Что до остального... во-первых, я мало видел тех, кому реально был нужен высоконагруженный хайлоад, так что и на ваш проект смотрю скептически, с таким-то уровнем вопроса. Не, вот без обид: где в вопросе конкретные цифры нагрузки хотя бы? И да, вопрос нужно перефразировать, чтобы можно было дать какой-то определённый ответ. С чего нужно начинать -- это больше вопрос нечёткого выбора, у каждого свои вводные, тут не угадать.

В чём разница между ГБ и ГиБ?

#информатика


В чём разница между единицами измерения информации ГБ и ГиБ?
    


Ответы

Ответ 1



гигабайт GB 1000000000 байт гибибайт GiB 1073741824 байт

Ответ 2



Разницы на самом деле две. Первая из них, как и отмечено в принятом ответе, состоит в том, что термины «килобайт», «мегабайт» и «гигабайт» по рекомендации IEC должны означать соответственно 1000, 1 000 000 и 1 000 000 000 байт. В отличие от них, термины «кибибайт», «мебибайт» и «гибибайт» должны означать 1024, 1024² = 1 048 576 и 1024³ = 1 073 741 824 байт. В реальности же (и в этом состоит вторая разница), «би»-варианты практически не применяются, и в повседневном общении килобайт, мегабайт и гигабайт означают чаще всего (но не всегда) именно 1024, 1024² и 1024³ байт. Это создаёт путаницу, но термины наподобие «кибибайт» настолько неблагозвучны, что с этой путаницей приходится жить дальше. Тем не менее, производители дисковых накопителей и чипов оперативной памяти часто используют для обозначения ёмкости своих устройств традиционные единицы («гигабайт»), употребляя их в смысле рекомендации IEC (то есть, у них 1 Гб = 1 000 000 000 байт). Критики утверждают, что это делается не столько для поддержки стандартизации, сколько из маркетинговых соображений.

Что означает запись вида 192.168.0.0/16 ?

#сеть


Помогите осознать значение /16.
Или вот пример из книги:
fe80::f00 = fe80:0000:0000:0000:0000:0000:0000:0f00
fe80::f00/64 = fe80:0000:0000:0000:****:****:****:****
             = fe80::/64
    


Ответы

Ответ 1



Это записи так называемых бесклассовых сетей. 192.168.0.0 - это понятная для людей запись четырехбайтовых адресов протокола Internet версии 4. /16 - означает первые 16 бит = 2 байта в этой записи - маска подсети. Другие два байта описывают адрес конкретного узла в этой подсети (от 0.1 до 254.254). 192.168.0.0/24 уже значило бы подсеть 192.168.0 с адресами внутри нее от единицы до 254. fe80::f00 = fe80:0000:0000:0000:0000:0000:0000:0f00 fe80::f00/64 = fe80:0000:0000:0000:****:****:****:**** = fe80::/64 Приведенный выше пример показывает краткую нотацию адресов протокола Internet версии 6. Как видно их принято записывать в виде шестнадцатеричных октетов разделенных двоеточиями. Два идущих подряд двоеточия означают большую последовательность нулевых октетов (байтов). /64 означает то же самое что и в версии 4 - маску подсети.

Ответ 2



Основывается эта радость на VLSM. Различают сеть (network, адрес сети), хост (host, адрес хоста) и маску сети (network mask), это разные три понятия. Маска по большому счету определяет границу между адресом сети и адресом хоста в этой сети. /16 это лишь длина маски, т.е. количество единичных бит слева (в скобках система счисления): /0 = 00000000.00000000.00000000.00000000(2) = 0.0.0.0(10) /1 = 10000000.00000000.00000000.00000000(2) = 128.0.0.0(10) ... /8 = 11111111.00000000.00000000.00000000(2) = 255.0.0.0(10) ... /16 = 11111111.11111111.00000000.00000000(2) = 255.255.0.0(10) ... /24 = 11111111.11111111.11111111.00000000(2) = 255.255.255.0(10) ... /32 = 11111111.11111111.11111111.11111111(2) = 255.255.255.255(10) В процессе наложения (битовое "и") маски на адрес (будь то сеть или хост) вы получаете адрес сети (именно сети). Т.е. в вашем случае, вы берете адрес 192.168.55.25 и маску 16-битной длины через битовое "и", получаете = 192.168.0.0 (ваша сеть). В десятичной системе: 192.168.55.25 & 255.255.0.0 = 192.168.0.0 В двоичной системе: 11000000.10101000.00110111.00011001 & 11111111.11111111.00000000.00000000 = 11000000.10101000.00000000.00000000 Вот как это работает. И используется это не в nmap для упрощения, а, например, в CIDR, не говоря уже о различных подсчетах и алгоритмах распределения адресного пространства. Что касается fe80::f00 = fe80:0000:0000:0000:0000:0000:0000:0f00 fe80::f00/64 = fe80:0000:0000:0000:****:****:****:**** = fe80::/64 Это действительно адрес в нотации IPv6. fe80 - это Link Local т.е. IP-адрес который может взаимодействовать только внутри локальной сети. /64 это также нотация CIDR аналогичная нотации в IPv4, которую я описал выше, только она несколько больше, так как IPv6 адрес = 128битам. Для Link-local: Минимальная длина маски - 10 (т.е. 10 неизменных бит с начала (слева)) fe80::/10 это диапазон fe80:0000:0000:0000:0000:0000:0000:0000 - febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff Для вашего случая: Т.е. для /64 первые 64 бита будут неизменными: fe80::/64 это диапазон fe80:0000:0000:0000:0000:0000:0000:0000 - fe80:0000:0000:0000:ffff:ffff:ffff:ffff Вот как-то так.

iOS или Android?

#android #ios


Не подскажите, что сейчас изучать перспективнее: iOS или Android? С точки зрения
востребованности у работодателей.    


Ответы

Ответ 1



И так вот подробный ответ с моими рассуждениями: iOS: Основной язык - Objective-C Магазин приложений - AppStore В магазине больше платных приложений чем бесплатных, пользователи охотно покупают приложения по приемлимой цене в 1-2$ Возможность разместить в приложении рекламу с большим охватом и прибылью, работать сразу с рекламными 10-12 компаниями и показывать всех их объявления (Обновление раз в 30 секунд, показ следующего). Предоставляет такой сервис как Mobclix. В данной сфере лично эффективность рекламы не тестировал Относительно дешевая и выгодная реклама приложений (Относительно эффективности не знаю) Нет проблем совместимости, пишется под один девайс, с одним размером экрана и набором функций При размещении приложений низкий % отказа пользователей, нет проблем совместимости, многие юзеры не качают приложение что бы 10 минут с ним поиграться. Android: Основный язык - Java Магазин приложений - AndroidMarket Пользователи не особо активно покупают платные версии приложений, из за открытости платформы предпочитают бесплатные версии. Возможность разместить в приложении рекламу с огромным охватом и прибылью, работать сразу с рекламными 8-9 компаниями(Включая OpenAllocation - AbMob, AdWords) и показывать всех их объявления (Обновление раз в 30 секунд, показ следующего). Предоставляет такой как сервис Mobclix. Если рекламодатель платит за показы или установки приложения иногда получается очень прибыльным занятием. Достаточно не дешевая реклама своего приложения (0.03-0.04$ за клик по баннеру,если платить за инсталлы то 0.25-1$ за установку) Проблемы совместимости, разные размеры экранов, разные версии системы, встречал даже такое что один функционал работающий на моем девайсе не работает на некоторых других моделях При размещении приложений и скачиванием их юзерами большой процент отказов, обычно даже бывает доходит до 40-50% (Следствием того является пункт выше + многие юзеры качают приложение "поразвлекаться")

Ответ 2



Ну, а сами чего вы хотите? Сейчас более востребован iOS. Но андроид очень быстро набирает обороты так, что вскоре андроид станет более преспективной платформой.

Ответ 3



Не стоит зацикливаться на одной платформе. Существуют проссплатформенные SDK для мобильных устройств, например, AirPlaySDK или Titanium. Они позволяют написать мобильное приложение один раз и скомпилировать его практически под все мобильные платформы.

Ответ 4



Под iOS можно не только на Objective-C писать, можно и на C# в Monotouch. Но без мака никуда... (говорят (c), что можно попытаться установить хакинтош ). На мой взгляд, оба эти направления перспективны. Плюс Андроида в том, что для него можно разрабатывать под виндой, то есть можно работать фрилансером или обучаться самостоятельно без ощутимых финансовых вложений.

Ответ 5



iOS но есть минус : надо иметь для 100% разработки Mac железо :) Вот я обладатель macbook о Xcode (objective-c) никогда не увлекался, только php, mysql & c++

Ответ 6



Лучше iOs так как там приложения активней покупают... А если перейдешь на мак, то про писи забудешь поверь мне)

Ответ 7



Да, iOS сейчас изучать перспективнее. Не думаю, что вскоре что-то изменится...

Для чего нужны файлы *.h?

#windows #cpp #visual_studio


Начинаю изучать Visual С++ (2010), раньше пользовался паскалем, поэтому:

не совсем понимаю, для чего нужны заголовочные файлы;
что конкретно в них прописывается (должно прописываться).
    


Ответы

Ответ 1



Если говорить применительно паскаля/делфи, то хедер - это фактически iterface секция, тогда *.с, *.cpp - это implementation часть. Грубо, конечно, но на первое время достаточно.

Ответ 2



Если константы, прототипы функций, макросы, объявления структур и тому подобная информация используется (является общей) в нескольких файлах с кодом программ, то ее помещают в .h файл, который включается в .c файлы (или другие .h) директивой препроцессора #include. Т.о. общие данные не дублируются. Они изменяются в одном месте и эти изменения согласованно включаются в коды программ.

Что происходит в оперативной памяти при прибавлении 1 к максимальному значению переменной?

#математика


Есть int  с максимальным значением 2147483647. В оперативке выглядит так:
11111111111111111111111111111111

При прибавлении единицы число превращается в -2147483647 и 
01111111111111111111111111111111

Из-за чего Происходит смена именно 1ой ячейки? Как выглядит этот процесс?
p.s. буду благодарен тому, кто посоветует подходящую метку    


Ответы

Ответ 1



Никакой мистики, просто дополнительный код. У вас небольшая ошибка: число 2147483647 в дополнительном коде выглядит как 0111 1111 1111 1111 1111 1111 1111 1111 (31 единица), а -2147483648 - 1000 0000 0000 0000 0000 0000 0000 0000 (единица и 31 ноль).

Ответ 2



Никакой мистики нету, это всё определяется стандартами языков программирования. В C++, например, переполнение знакового целого является undefined behaviour, то есть, программа некорректна, и может случиться всё, что угодно, включая получение того ответа, который вы ожидали, любого другого ответа, снос операционной системы и появление привидений из дисковода. Обычно, однако же, n-разрядные целые в C++ (да и во многих других языках) ведут себя как остатки по модулю 2^n: при вычислении "переполненного" значения разряды старше n-го просто отбрасываются. Для вашего случая, 2147483647 (двоичное 0111 1111 1111 1111 1111 1111 1111 1111) превращается в -2147483648 (двоичное 1000 0000 0000 0000 0000 0000 0000 0000). Но надеяться на это не стоит: компилятор имеет право воспользоваться тем, что в случае UB он может генерировать любой код, для более мощной оптимизации. Заметьте, что переполнение беззнакового целого в C++ — определённая и допустимая вещь: при переполнении число "законно" заменяется на остаток при делении на 2^n. В C# стандарт языка диктует другое правило: в непроверяемом контексте переполнение приводит к неявному взятию остатка по модулю 2^n; в проверяемом же контексте переполнение приводит к исключению. Пример: public class Test { public static void Main() { int maxint = 2147483647; int increased1 = unchecked(maxint + 1); Console.WriteLine("increased1 = {0}", increased1); int increased2 = checked(maxint + 1); Console.WriteLine("this will never be reached"); } } Здесь работает только первое переполнение, программа выдаёт increased1 = -2147483648 после чего срабатывает исключение. В Java переполнения примитивных типов исключены стандартом, результат не отличается от C# в непроверяемом контексте.

Объясните наглядно разницу раннего и позднего связывания методов.

#java


Позднее связывание методов это когда имеется ссылочная переменная, и в зависимости
от того экземпляр какого класса будет создан, и будет вызван соответствующий метод.
А как насчет раннего связывания в чем отличие?    


Ответы

Ответ 1



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

Ответ 2



Раннее связывание, как было отмечено выше, происходит на этапе компиляции. Оно применяется при вызове обычных методов (не виртуальных). Позднее связывание напротив происходит во время выполнения. Выполняется оно при вызове виртуальных функций класса-потомка для определения того, какой именно метод следует вызывать. Исходя из того, что раннее связывание выполняется на этапе компиляции, а позднее - в рантайме, первый вариант обладает лучшим быстродействием, однако второй необходим для реализации полиморфизма. По поводу Java могу сказать, что там, если не ошибаюсь, ко всем методам по умолчанию применяется позднее связывание (если они не помечены модификатором final) в отличие от, скажем, С++, где по умолчанию применяется раннее связывание. Еще для большего понимания вопроса почитайте про таблицу виртуальных методов З.Ы. с Java близко не знаком, поэтому точно не могу сказать, насколько там применим термин "функция"

Json как парсить на Java?

#java #json #синтаксический_анализ #json_encode


Здравствуйте!
Есть вот такой ответ от сервера: 

 {
    "p_result": "ok",
    "p_item": [
        {
            "p_id": 132,
            "p_name": "Николай"
        }, 
        {
            "p_id": 133,
            "p_name": "Светлана"
        }
    ]
 }


Если правильно понимаю, то это массив.
Нужно написать метод который будет по параметру находить нужный элемент
что то наподобие : 

_http.getArrayParamValue("p_name");


Никак не могу сообразить.

p.s. думаю для меня было бы полезнее некое указание, нежели ссылка на очерендую библиотеку.
Спасибо!

Решение. Ошибку тоже понял. @Josfey Спасибо огромное. Вы очень мне помогли! 

String str = null; 
String input = "данные полученные от сервера"; 

JsonParser parser = new JsonParser(); 
JsonObject mainObject = parser.parse(input).getAsJsonObject();
JsonArray pItem = mainObject.getAsJsonArray("p_item"); 

for (JsonElement user : pItem) {

    JsonObject userObject = user.getAsJsonObject(); 
    userObject.get("p_id"); 
    str = userObject.get("p_id").toString(); 
}

    


Ответы

Ответ 1



Не совсем понял, что именно вы хотите извлечь из приведённой json-структуры, но вот, например, как извлечь из неё имя пользователя c id = 132 с помощью GSON. String input = "тут ваша json-структура"; JsonParser parser = new JsonParser(); JsonObject mainObject = parser.parse().getAsJsonObject(); JsonArray pItem = mainObject.getAsJsonArray("p_item"); for (JsonElement user : pItem) { JsonObject userObject = user.getAsJsonObject(); if (userObject.get("p_id").getAsInt() == 132) { System.out.println(userObject.get("p_name")); return; } }

Ответ 2



На мой взгляд, самая лучшая на данный момент библиотека для работы с JSON - это Jackson от fasterxml. Измерял скорость сериализации/десериализации с помощью JMH, и эта библиотека показала наилучшие результаты на довольно сложной структуре данных. Кроме того, она имеет довольно богатый набор настроек: интернирование ключей, реакция на ошибки синтаксиса и т.п. Если вы хотите не просто сериализовывать/десериализовывать JSON-документы, а хотите менять структуру JSON-документа на лету, то рекомендую GSON.

Ответ 3



Рекомендую обратить внимание на json-simple Вот тут пример использования

Как правильно опубликовать проект, содержащий базу данных?

#база_данных #git #github #веб_программирование


Часто на собеседованиях или перед ними просят показать какой-нибудь свой код. Я хочу
написать для этих целей какой-нибудь небольшой проект и разместить его например на GitHub.

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

Скажите пожалуйста как можно залить бд на GitHub, чтобы любой человек при желании
мог целиком собрать рабочее приложение? Или  может есть другие способы? Спасибо!
    


Ответы

Ответ 1



вероятно, бо́льшая часть систем управления базами данных обладает возможностью сделать dump базы данных, содержащий всю необходимую информацию для последующего воссоздания базы. причём, как правило, такой dump сохраняется в текстовом виде, т.е. представляет собой неплохой объект для систем управления версиями, которые лучше всего «обращаются» именно с текстовой информацией. некоторые субд могут даже предоставлять специальные опции для улучшения такого рода хранения (в системах управления версиями). например, у программы mysqldump есть опция --skip-extended-insert, благодаря которой в dump-е генерируется отдельный оператор insert для каждой строки данных. без неё все строки таблицы заносятся одним, очень-очень длинным оператором insert, что, естественно, создаёт определённые трудности для, например, сравнения отличий между двумя dump-ами.

Ответ 2



В принципе, в репозитории Git можно сохранить что угодно, в том числе бинарные файлы базы данных. Но Git хранит целые файлы, а не дельты. И тем более он не сможет сохранять изменения в том виде, в котором его воспринимают СУБД. Т.е. Для СУБД: Найти поле X, записать в него значение Y изменение в несколько байт. старая версия удаляется Для Git: Полностью удалить файл и заменить его новым. изменение в много мегабайт все версии сохраняются. Таким образом, если вы будете сохранять в коммитах последовательно несколько состояний БД, то каждое будет целиком и навсегда сохранено в репозитории. Это очень быстро раздует его размеры. Что было бы лучше: написать SQL / DDL код, инициализирующий базу данных в том виде, в котором она нужна для работы приложения Написать инструкцию по установке или скрипт для автоматизации установки (плюс в глазах работодателя) Публиковать в репозитории этот код и документацию (ну и само приложение). Вариант 2: Опубликовать проект одним коммитом, без истории. Ссылки: Хранение схемы MySQL в репозитории Git (eng)

Ответ 3



Храните в репозитории только структуру и миграции, а дамп с данными (не думаю что у вас большая база) залейте в релизы на github или на bintray, и укажите ссылку на базу в описании README.MD

Ответ 4



Способ, который будет удобен даже в production, и который выставит вас в выгодном свете, будучи применённым в демо: Создаёте дамп структуры базы данных. Как уже было сказано, это текстовый файл. В структуре базы имеет смысл указать версию этой структуры (например, создать представление с одним селектом одной константы). Создаёте дамп тестового набора данных. Тоже текстовый файл, с INSERT'ами. (Опционально) Создаёте скрипт, обновляющий старую структуру базы до новой, на основании информации о версии структуры. Создаёте программу, каким-то образом имеющую параметры подключения к серверу и имя БД. При запуске программа подключается к серверу, проверяет версию сервера, смотрит есть ли БД. Если старая версия сервера - откланивается. Если нет базы - предлагает создать (с помощью скрипта; если выбрана галочка внесения в базу тестовых данных, то следом вносятся тестовые данные). Если старая версия структуры - предлагает обновить (с помощью скрипта). Далее программа работает как обычно. При веб-разработке, "программа" это скорее всего страница в "/admin".

Ответ 5



Ответ очень сильно зависит от платформы, которую вы используете. Если вы (случайно) пишете на C#/.NET, то на гитхаб можно просто так взять и залить базу данных - mdf/ldf файлы с подключением в приложение через AttachDbFileName в строке соединения. В заданных рамках - выложить куда-то пример своего кода, который можно будет забрать/показать/запустить без лишних телодвижений - это более чем подходящее решение. Если вы при этом еще и используете Entity Framework Code First - то ваше приложение и так уже умеет создавать базу данных, и ничего никуда заливать не нужно. На всякий случай стоит использовать имя сервера (localdb)\v11.0 в обоих вариантах - этот инстанс с большой вероятностью есть на машине с Visual Studio, и приложение можно будет запустить сразу после скачивания исходников.

Ответ 6



База данных может быть построена по стандарту JSON-LD. Физически это обычные директории ("наборы данных") и json-ки в них. Соответственно, отлично будет работать прямо в склонированном репо.

Ответ 7



Для начала Вам необходимо выгрузить текущее состояние базы данных в виде дампа сриптов описания сущьностей, и затем придумать каким образом это всё менеджить в Вашей системе контроля версий. Мне нравится подход описанный в блоге Scott Allen В кратце, создаётся baseline - папка начального состояния с дампами описаниями структуры таблиц. Среди Ваших таблиц создаётся таблица для журнала версий к примеру SchemaChanges. В этой таблице будут отображаться изменения произведённые уже на данной БД. После такой подготовки создаётся папка изменений БД в которую вносятся изменения существующей схемы. Каждое изменение схемы должно добавлять свою версию в журнал изменений. Для работы с другими сущьностями БД как view, trigger, хранимые процедуры и функции Скот предлагает сделать для них отдельную папку и накатывать их после каждого изменения структуры бд, тем самым проверяя не нарушилось ли состояние базы. Достаточно сложно, но тем не менее достаточно стабильно и не требует особо больших усилий, кроме как для написания утилиты для запуска скриптов. Более подробно и на русском можно почитать перевод. Сейчас достаточно много платных утилит призвано решить эту проблему к примеру утилиты red gate или apexsql. Ищите подход который больше подходит Вам.

Старший бит числа 0 в двоичном представлении

#типы_данных


Почему при кодировании числа 0, он записывается именно как положительный 0, т.е.
0.0000000? А не, допустим, отрицательный (со старшим битом равным 1 - 1.0000000).
Рассматриваются целочисленные типы данных со знаком.

Исторические предпосылки? Или это связано с выполнением арифметических опеоаций в
двоичном виде?
    


Ответы

Ответ 1



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

Ответ 2



Это зависит от платформы и представлении в ней целых чисел. Некоторые платформы поддерживают во внутреннем представлении целых чисел отрицательный ноль. Из стандарта языка C (6.2.6.2 Integer types): ...In the case of sign and magnitude and ones’ complement, if this representation is a normal value it is called a negative zero. 3 If the implementation supports negative zeros, they shall be generated only by: — the &, |, ^, ~, <<, and >> operators with operands that produce such a value; — the +, -, *, /, and % operators where one operand is a negative zero and the result is zero; — compound assignment operators based on the above cases. It is unspecified whether these cases actually generate a negative zero or a normal zero, and whether a negative zero becomes a normal zero when stored in an object. Просто самые распространенные платформы имеют внутреннее представление целых чисел в виде дополнения до 2^n, для которого либо представление, в котором знаковый бит установлен, а все другие биты равны нулю не является допустимым значением (trap value), либо является отрицательным числом.

Что выбрать ASP.NET MVC или SharePoint для Enterprise? [закрыт]

#c_sharp #aspnet #aspnet_mvc #sharepoint


        
             
                
                    
                        
                            Closed. This question is opinion-based. It is not currently
accepting answers.
                            
                        
                    
                
                            
                                
                
                        
                            
                        
                    
                        
                            Want to improve this question? Update the question so
it can be answered with facts and citations by editing this post.
                        
                        Closed 1 год назад.
                                                                                
           
                
        
На работе необходимо будет реализовать систему аналитической отчетности. Содержащую
различные отчеты с множеством данных, полей колонок и фильтром, детальных отчетов и
т.д. Сейчас она реализована в собственной системе отчетности, но руководители хотят
видеть более современный дизайн и поддержку в браузерах. Так же в данный момент система
работает в локальной сети организации, но будет необходимо реализовать доступ к отчетам
через сеть Интернет.

Изначально в планах было реализовать систему на ASP.NET MVC 5. Но руководство вспомнило
что в предприятии куплен SharePoint (2010 или 2013). Он интегрирован с Lync и Outlook,
что удобно. Встал вопрос что использовать.

Разрабатывать систему придется начинать мне. Дали время решить что лучше использовать.
Но опыт есть только в ASP.NET MVC. После прочтения некоторых статей, стал сомневаться
в своем изначальном выборе MVC. SharePoint так же показался привлекательным со своими
плюсами.

Систему что на ASP.NET MVC, что на SharePoint придется реализовывать с нуля. Выбор
технологии для разработки системы предстоит сделать из стека Microsoft.

Очень важно услышать мнение более опытных и авторитетных людей на счет.

Если можно, то выскажитесь в соответствии с вашим опытом или знаниями, как ASP.NET
MVC и SharePoint подходят под эти критерии:


Создание удобного пользовательского интерфейса (скорее простота создания, т.к. скорее
всего будет использован Bootstrap;
Простота и скорость разработки (если учесть что разработка будет с нуля и мои познания
ограничиваются ASP.NET MVC);
Возможность простого развертывания и настройки сервера для доступа из сети Интернет;
Настройка безопасности:  авторизации, роли,  шифрование и т.п.;
На что еще нужно обратить внимание?

    


Ответы

Ответ 1



Если есть возможность - не используйте sharepoint! Мы сейчас делаем на нем сложный проект - и стабильно каждую неделю случается, что что-то в шарике просто не работает из-за неучтенных изменений, накопившихся в нем ранее. (Пример - сейчас не могу создать lookup field ни в одном списке через веб-интерфейс из-за того, что не загружается список списков - а не загружается он потому что какой-то из списков где-то на сайте "битый"). Если делать для шарика решение - это тихий ужас. Вместо современного ASP.NET MVC - устаревший ASP.NET WebForms. Шарик должен стоять на каждом компе разработчика - иначе студия не сможет даже открыть проект. Шарик должен стоять даже на билд-агенте! Иногда общую для нескольких проектов сборку приходится деплоить в GAC. После этого эту сборку надо обновлять в GACе каждый раз перед использованием - то есть нельзя даже консольную утилиту отладить или тесты прогнать без деплоя решения на сервер. С автоматическим деплоем - тоже веселье. После установки решения на ферму надо отдельно активировать его возможности (они же фичи). Причем активировать их нельзя пока решение не установится полностью - а команды дождаться нету. Более того, нет простого и очевидного способа определить, устанавливается сейчас решение или не смогло установиться - в обоих случаях будет статус NotDeployed. Кстати, можно запросто удалить решение без деактивации его фич. После этого фичи уже невозможно деактивировать (да, вот так у меня на рабочем компе и появился битый список из первого абзаца). Если же делать для шарика не решение, а приложение - то всей этой радости, разумеется, не возникает. Но и возможностей тут куда меньше. И тут возникает другой вопрос... Каждое приложение - отдельный сайт. Зачем приложению вообще нужен шарик, что от него можно получить? Авторизация пользователей? Но шарик использует внешнюю STS для этих целей, без нее просто не будет работать связь с приложениями. Но тогда и текущего пользователя можно узнавать не у шарика, а у STS. Хранилище данных? Но у шарика очень тормозные списки. Что неудивительно, если покопаться в их внутреннем устройстве. Управление конфигурацией? Но если делать автоматическое развертывание - то шарик не упрощает процесс, а лишь ставит палки в колеса. В итоге получается, что шарик как платформа не может предоставить ничего интересного, что можно было бы использовать. В каком же случае шарик имеет смысл использовать? Использовать его имеет смысл, если он в архитектуре является не платформой, а приложением. Если в числе стандартных или сторонних, но уже готовых решений есть именно то, что вам надо. В таком случае имеет смысл использовать это самое готовое решение, и дорабатывать его или с ним интергироваться. Но не следует помещать его в центр своей архитектуры. UPD. По пунктам из вопроса. Пользовательский интерфейс на WebPages делать удобнее нежели на WebForms. А решения шарика используют WebForms. Разрабатывать решения под шарик очень сложно. В документации на msdn нет даже такой важной информации, какие объекты надо закрывать, а какие не надо. Точнее, информация есть - но в отдельной статье, а не в доках по классам. И все такие статьи придется найти и выучить. Установка решения на шарик вручную, через веб-интерфейс - довольно простая. Но ее автоматизация - это ад. Кроме того, само по себе развертывание шарика - тоже тот еще ад. У шарика есть красивый веб-интерфейс для редактирования прав. Но только для встроенных в шарик же объектов. У ASP.NET MVC куда больше возможностей по управлению безопасностью именно с точки зрения программиста. Разумеется, все вышеперечисленное относится к решениям шарика, а не приложениям. Приложение пишется на том же ASP.NET MVC и лишено подобных недостатков. Но тут мы возвращаемся к проблеме "зачем вообще приложению шарик".

Ответ 2



Если у Вас уже куплен SharePoint – то это может позволить реализовать типовое решение довольно быстро. Если бы Вы уточнили, что имеется в виду под «необходимо будет реализовать систему аналитической отчетности», то можно было бы посоветовать что-то более конкретное. SharePoint довольно гибок, хотя Вам нужно также уточнить, какая именно версия имеется: 2010 или 2013, т.к. между ними большая «пропасть» - а заключается она именно в концепции разработки под данную платформу. В версии 2013 подходы к написанию приложений кардинально поменялись. Я склоняюсь к SP, т.к. в нем уже реализована часть базового функционала, а именно: система ролей, библиотек и списков (включая версионность, синхронизацию, административный интерфейс и т.п.). Многое можно реализовать вообще без программирования (за 10 лет администрирования SharePoint программировать приходилось лишь раз 5). Часть задач можно реализовать через SharePoint Designer. Но опять же, уточните ТЗ, тогда можно будет сказать подробнее, какие именно инструменты SP можно использовать, а что нужно допрограммировать. По пунктам: Натянуть свой шаблон на SP – не самая тривиальная задача, т.к. часть компонентов уже имеют свой дизайн Разработка может вообще не понадобится, но если и понадобится, то со знанием .Net проблем не должно быть Простота установки SP зависит от количества развертываемых ферм Система ролей реализована достаточно хорошо Зависит от ТЗ

Ответ 3



SharePoint можно воспринимать как CMS c прикрученными Enterprise службами, которые прекрасно в него интегрированы. При этом SharePoint является отличной платформой для разработки в "кровавом ентерпрайзе". Многое, что Вам нужно делать самостоятельно на ASP.NET MVC, в SharePoint делается в "пару кликов". Есть списки, формы к ним, настраиваемые представления, поиск, настройка прав, создание страниц, Web parts, Timer job'ы, Event receiver'ы и еще много очень полезных вещей. Так же стоит отметить возможность быстрой масштабируемости, можно выносить звенья фермы на другие сервера. Используя SharePoint, можно поставлять значимые для бизнеса решения, делать это быстро и с приемлемым качеством. Что касается работы с отчётностью - изучите службы Performance point. Нам удалось с помощью этой службы создать наглядные панели мониторинга. Чем SharePoint плох: SharePoint сложен. Правда. И это требует большого объёма знаний для работы с ним. Обилие возможностей и порождает его сложность. Так же, механизмы SharePoint часто дают очень быстрый старт в начале, а позже можно "упереться" в ограничения "by design". Он использует ASP.NET WebForms, а не ASP.NET MVC. При расширении функционала кодом - надо вписываться в архитектуру SharePoint. Развертывание созданных Вами артефактов (Provision) - еще больше удручает, надо писать кучу XML. Но сейчас уже есть SPMeta (Библиотека и расширение для VS), которая сильно упрощает процесс. Как говорят, самый короткий путь — тот, который знаешь. Используйте ASP.NET MVC и купите контролы для работы с отчётностью. Но Performance point все же посмотрите, может подойдёт. Что касается ответов по пунктам - я полностью согласен с @Ella Svetlaya

Для чего пишут модификаторы private static для переменных?

#java #android


Для чего пишут модификаторы private static для переменных?


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


Но если private static, выходит что-то подобное: "Переменная статическая, чтобы другие
классы могли использовать ее, не создавая экземпляр класса, но я не разрешаю использовать
ее другим классам!". В чем смысл? :D

P.S. Вопрос из раздела Java, но, в основном, я встречаюсь с этим в Android`e, в нем
нет никаких нюансов?
    


Ответы

Ответ 1



Модификатор private означает, что член класса с данным модификатором доступен только объектам данного класса внутри его реализации, включая его методы. То есть за пределами определения класса он не доступен. Модификатор static означает, что член класса с этим модификатором является общим для всех объектов этого класса. То есть для всех объектов этого класса создается единственный экземпляр этого члена. Все объекты этого класса совместно используют этот единственный экземпляр. Но тем не менее вы можете его сделать, например, открытым для внешнего мира (public), или же закрытым (private), чтобы только объекты этого класса имели к нему доступ. То есть функции этих модификаторов различны и не зависят друг от друга. Первый модификатор определяет доступ к члену класса. Второй модификатор определяет, что все объекты данного класса будут совместно использовать член класса, который определяется в единственном экземпляре за пределами каждого объекта.

Ответ 2



private означает что поле доступно только в пределах самого класса - т.е. только методам класса, в котором оно объявлено. static означает что поле не привязано к конкретному экземпляру класса, а является общим для всех экземпляров. private static - общее для всех экземпляров класса поле, работать с которым можно только из методов этого класса. Типичный пример использования - реализация Singleton: public class Singleton { private static Singleton instance; public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } Ограничение доступа к private static Singleton instance + явное управление инициализацией позволяет гарантировать, что вызов Singleton.getInstance() всегда будет возвращать один и тот же объект. Будь поле не static - вызов возвращал бы разные объекты (и вообще поле из него нельзя было бы использовать). Будь поле не private - кто угодно мог бы влезть и переписать его значение на новый объект.

Ответ 3



В дополнение к другим ответам: Утверждение Если модификатор static, тогда переменная доступна другим классам, без создания экземпляра класса, в котором переменная неверно! Правила доступности к полю/методу с модификатором static определяются, как и всегда, ключевыми словами private/protected/public. Ключевое слово static лишь означает, что если доступ есть, то он будет через имя класса (поправка для Java: возможен через имя класса), а без этого — лишь через конкретный объект (возможно, this).

Ответ 4



private static чаще всего используется для переменных, которые не будут видны из другого класса. Например: private static String JDBC_URL = "jdbc:mysql://localhost/shopdb"; private static String JDBC_USERNAME = "username"; private static String JDBC_PASSWORD = "password";

Ответ 5



private - переменная доступна только внутри класса. Ее могут использовать другие переменные и все методы класса (в теории все, но на практике вряд ли). static - означает что для всего множества объектов класса переменная будет общей. т.е. есть static String name = "Вася" object1.name = "Вова" установит значение переменной name во всех объектах класса равной "Вова"

Проверить html цвет на валидность

#php #html


Есть поле INPUT, в который вводится цвет вида fff (обязательно без "#" она подставляется
в самом html).

Из него данные передаются в PHP и там в HTML прямо подставляется то значение, как
его правильнее фильтровать?
И сделать чтобы если оно невалидное, то подставлялось стандартное значение?
    


Ответы

Ответ 1



Проверить валидность можно регуляркой. Например такой, так как цвет можно задавать как 3-мя, так 6-ми символами: /^([a-f]|[A-F]|[0-9]){3}(([a-f]|[A-F]|[0-9]){3})?$/i Как-то так: $color; // тут у вас строка с цветом if(preg_match('/^([a-f]|[A-F]|[0-9]){3}(([a-f]|[A-F]|[0-9]){3})?$/i', $color)){ // валидный цвет } else{ // не валидный цвет }

Ответ 2



Экономим на спичках! preg_match() считается медленной функцией. Быстрее проверить длину строки (только 3 или 6), а затем ASCII код каждого символа в строке: = 97 && $code <= 102) continue; // a-f if( $code >= 65 && $code <= 70) continue; // A-F if( $code >= 48 && $code <= 57) continue; // 0-9 return false; } return true; } Ideone с тестами.

Ответ 3



Можно проще: function validate_color($str){ return (($l=strlen($str))==3)||($l==6)) && sscanf($str,"%x", $color); } print(validate_color("AAA")? "цвет валидный": "цвет не валидный"); P.S. Снимаем вопросы по быстродействию: function validate_color_sscan($str){ return ($l=strlen($str)) && (($l==3)||($l==6)) && sscanf($str,"%x", $color); } function test_sscan($str){ for($i=0; $i<2000000; $i++) $v=($l=strlen($str)) && (($l==3)||($l==6)) && sscanf($str,"%x", $color); } function validate_color_preg($str){ return preg_match('/^[A-F0-9]{3}([A-F0-9]{3})?$/i', $str); } function test_preg($str){ for($i=0; $i<2000000; $i++) $v=preg_match('/[a-f0-9]{3}([a-f0-9]{3})?$/i', $str); } print(validate_color_sscan("AAA")? "
цвет валидный": "
цвет не валидный"); print(validate_color_preg("AAA")? "
цвет валидный": "
цвет не валидный"); $time0 = microtime(true); test_sscan($str); $time1 = microtime(true); test_preg($str); $time2 = microtime(true); printf("
test_sscan x 2000000: %d mcs", $time1-$time0); printf("
test_preg x 2000000: %d mcs", $time2-$time1); Результаты: цвет валидный цвет валидный test_sscan x 2000000: 8 mcs test_preg x 2000000: 14 mcs

Ответ 4



preg_match('/^([a-f0-9]{6}|[a-f0-9]{3})$/i', $color)

Ответ 5



Хотелось найти еще какой-либо альтернативный вариант, помимо регулярных выражений. Откопал функцию ctype_xdigit() - проверяет, является ли строка шестнадцатеричным значением (без символа решетки). Не ручаюсь на счет производительности, не пользовался ей. ctype_xdigit('fff'); // true

Зачем нужен встроенный делегат Func?

#c_sharp


При решении очередной проблемы опять сталкнулся со встроенным делегатом Func. Никак
не могу понять его предназначение, как он работает и как устроен. Может кто-то на каком-то
простом примере объяснить что это, для чего используется, как это работает и как этим
пользоваться?
    


Ответы

Ответ 1



Допустим мы имеем метод, который рисует графики различных функций, для простоты - алгебраических, вида y=f(x). Нашему методу все равно какую именно функцию данного вида рисовать, главное чтобы вид функции совпадал с заданным. тогда мы можем определить наш метод следующим образом: public void DrawFunc(Func f) { for(double x = 0.0; x<1.0; x+=0.001) { double y = f(x); //и далее рисуем точки графика } } Теперь для отрисовки графика нам нужно вызвать наш метод и передать ему подходящую функцию. Для Func< double, double> нам подойдет любая функция вида double FuncName(double ParamName), например Math.Sin. Вызов будет выглядеть так: DrawFunc(Math.Sin); Данный делегат, как и аналогичный ему Action используется в основном для быстрого объявления делегатов стандартного вида. Определено несколько отдельных делегатов вида Func< T1,...,T16,TResult>, и Action< T1,...,T16> которые могут принимать до 16-ти параметров (.NET 4+, до 4-х для .NET 3.5), типы которых указываются при объявлении. Кроме этого для Func необходимо указать тип возвращаемого значения TResult, у Action возвращаемое значение всегда void. Больше ничем от обычных делегатов они не отличаются. тут уже обсуждалась очень похожая тема и есть еще немного информации

Ответ 2



В дополнение к правильному ответу @rdorn: Func<> — это по существу (с мелкими отличиями) тип, описывающий функцию. Вы можете передавать в другой метод или класс не только данные, но и код. Для этого вам нужно описать его тип, чтобы его можно было присваивать параметру, записывать в переменные или возвращать из функций. Вот Func<> именно для этого и служит. Пример: // применяет функцию дважды к начальному значению и выводит результат void ApplyTwiceAndPrint(Func f, int value) { int result1 = f(value); int result2 = f(result1); Console.WriteLine(result2); } ApplyTwiceAndPrint(n => n * n, 3); // выводит 81 Как именно это работает внутри? Внутри Func<...> является объектом типа MulticastDelegate, у которого определена функция Invoke(...). Когда вы пишете f(value), компилятор поставляет вместо этого f.Invoke(value), то есть, вызывает метод Invoke. (Да, тут есть немного компиляторного «сахара», которого нету, скажем, у Java.) Внутри объект типа MulticastDelegate хитрым системно-зависимым образом содержит по сути указатель на метод, который и будет вызван в реализации метода Invoke.

Как правильно парсить с помощью AngleSharp?

#c_sharp #html #css #anglesharp


Всем привет! Много тем уже перечитал похожих, но в них в основном какие-то частности
спрашивались. Очень согласен вот с этими словами. Ну, честно говоря, вообще ничего
непонятно. Понял, что информация из html парсится либо через LINQ, либо через CSS селекторы.
С первым вообще не знаком, CSS знаю поверхностно. Но все равно такой вариант мне интуитивно
что ли ближе, поэтому хотелось бы ответы получить в виде CSS селекторов.  

Сразу вопрос: всю ли инфу можно запарсить обоими способами? Или есть только случаи,
когда работает только один из способов? Или же есть случаи, где вообще нельзя?)  

Теперь непосредственно к задаче. Хочу запарсить данные контактов с сайта домофонда.
Например, возьмем вот эту страницу. Парсю всю страницу для начала

var parser = new HtmlParser();
var doc = parser.Parse("ссыль");


Как, например, запарсить имя? Смотрю исходник, вижу, что имя находится в блоке
div class="df_panel". Вроде бы этот блок с уникальным названием, поэтому можно сузить
поиск

var div = doc.QuerySelector("div.df_panel");


Вот тут сразу начинаются вопросы. Сам разобрался, что, если в блоке div указывается
название класса, то пишется так, как приведено. Если, например, div id="test", то уже
запрос по-другому пишется (долго доходило на основе кучу примеров из разных форумов)

var div = doc.QuerySelector("div[id="test"");


Вот где по этому поводу что-то написано? Я так понимаю, что здесь применяются какие-то
регулярные выражения. Может они аналогичные каким-то другим парсерам, как, например,
написано тут, что AngleSharp очень похож на Fizzler. Но что, если у меня это локально
возникшая задача, и не с какими другими парсерами я дело не имел? Как я должен понять,
что именно мне писать?  

Ладно, отвлекся. Див ближайший для сужения круга поиска получили. (Опять отвлекусь
- кстати, а как быть, если бы его вообще не было? Можно ли каким-то образом получить
определенные данные, если нет уникальных идентификаторов, посредством которых сужается
постепенно зона поиска нужного значения?). Итого видим, что имя записано в тег заголовка
НУЖНОЕ ИМЯ
. Как получить это значение? Было бы возможно вытащить имя, если бы оно было записано вообще без тега заголовка? Пока на этом вопросы задавать перестану. Буду благодарен за любые объяснения. Желательно очень получить ответы на более общие вопросы (например, по поводу, как я предполагаю, этих регулярных выражений с хелпом или хорошими примерами), тогда может с остальной частью я и сам разберусь.


Ответы

Ответ 1



Самое важное Перво-наперво, вам нужно выучить CSS селекторы. А для лучшего понимания, хотя бы еще основы HTML. Сделать это можно, например, на HTML Academy. Бесплатно. Я бы еще добавил, что никакой магии нет- все выборки AngleSharp это стандартные селекторы CSS, а не что-то необычное. (c) ReinRaus Отвечу на ваш вопрос: Но что, если у меня это локально возникшая задача, и не с какими другими парсерами я дело не имел? Как я должен понять, что именно мне писать? Чтобы понять, что надо писать, повторюсь, вам надо выучить CSS селекторы. Сделать это можно, например, здесь: "Знаете ли вы селекторы?". Приведу здесь краткую выжимку из упомянутой выше статьи: Основные виды селекторов Основных видов селекторов всего несколько: * – любые элементы. div – элементы с таким тегом. #id – элемент с данным id. .class – элементы с таким классом. [name="value"] – селекторы на атрибут (см. далее). :visited – «псевдоклассы», остальные разные условия на элемент (см. далее). Селекторы можно комбинировать, записывая последовательно, без пробела: .c1.c2 – элементы одновременно с двумя классами c1 и c2 a#id.c1.c2:visited – элемент a с данным id, классами c1 и c2, и псевдоклассом visited Отношения В CSS3 предусмотрено четыре вида отношений между элементами. Самые известные вы наверняка знаете: div p – элементы p, являющиеся потомками div. div > p – только непосредственные потомки Есть и два более редких: div ~ p – правые соседи: все p на том же уровне вложенности, которые идут после div. div + p – первый правый сосед: p на том же уровне вложенности, который идёт сразу после div (если есть). Селекторы атрибутов На атрибут целиком: [attr] – атрибут установлен, [attr="val"] – атрибут равен val. На начало атрибута: [attr^="val"] – атрибут начинается с val, например value. [attr|="val"] – атрибут равен val или начинается с val-, например равен val-1. На содержание: [attr*="val"] – атрибут содержит подстроку val, например равен myvalue. [attr~="val"] – атрибут содержит val как одно из значений через пробел. Например: [attr~="delete"] верно для edit delete и неверно для undelete, а еще неверно для no-delete. На конец атрибута: [attr$="val"] – атрибут заканчивается на val, например равен myval. Где попрактиковаться? CSS Diner - здесь нужно выбирать элемент, соответствующий указанному CSS правилу. HTML Academy - здесь можно изучить основы верстки. htmlbook - справочник по css селекторам и html тегам. Ответы на остальные вопросы Вот где по этому поводу что-то написано? Я так понимаю, что здесь применяются какие-то регулярные выражения. Это не регулярные выражения, а CSS селекторы. Об этом я написал выше. Можно ли каким-то образом получить определенные данные, если нет уникальных идентификаторов, посредством которых сужается постепенно зона поиска нужного значения? Да, комбинируя дочерние элементы по любому признаку. Например, первый потомок в родителе (* > *:first-child), точно второй по счету элемент p внутри своего родителя (p:nth-child(2)), не пустой a элементы (a:not(:empty)) и так далее. Итого видим, что имя записано в тег заголовка
НУЖНОЕ ИМЯ
. Как получить это значение? Было бы возможно вытащить имя, если бы оно было записано вообще без тега заголовка? Если я правильно понял, и имеется в виду значение, не обернутое в какой-либо тег, то все равно ответ будет – да. Можно выполнить поиск по тексту. Для этого конкретного случая решение в виде селектора будет таким: h6[itemprop="name"] как только не пробовал. Не парсит с .df_panel Ваш код из комментариев использует метод QuerySelector, который, как я понимаю, выбирает первый элемент с указанным селектором. Первый .df_panel из шести на странице не содержит элемента h6. Поэтому у вас ничего и не находит. Еще раз подчеркну: на странице шесть элементов .df_panel. Код для выборки нужного вам элемента var seller = doc.QuerySelector("[itemprop='seller']"); var name = seller.QuerySelector("[itemprop='name']").Text();

Ответ 2



Но что, если у меня это локально возникшая задача, и не с какими другими парсерами я дело не имел? Как я должен понять, что именно мне писать? Выше ответили про то, что вам нужно знать css селекторы, однако поскольку вопрос светится в поисковиках (вопросов на ru-so не так много) - допишу ещё полезную ссылку по теме. В официальных репозиториях AngleSharp на гитхабе есть демо-приложение.

std::next vs std::advance

#cpp


Почему std::next дефолтно продвигает на 1, а std::advance - нет? 
    


Ответы

Ответ 1



Я уже делал такое предложение комитету стандартизации по C++. Я описал данное несоответствие на своем форуме в теме std::advance и std::bitset - два простых предложения по стандарту C++ Номер этого предложения №4369. К сожалению я не отслеживал судьбу этого предложения. Формально предварительно в обсуждении оно было одобрено, но, как всегда, в комитете есть люди которые считают лишь собственные предложения самыми важными и ревниво относятся к другим предложениям. Поэтому я сейчас не в курсе, какова судьба моего предложения. Но явных причин не делать аргумент по умолчанию для второго параметра я не вижу и не встречал какие-либо серьезные возражения со стороны других оппонентов.

Ответ 2



Эти функции служат несколько разным целям и появились по совершенно разным причинам. std::advance - функция старая (С++98), которая предназначалась для унификации итераторов разных категорий в generic алгоритмах, и в первую очередь в тех ситуациях, когда итератор надо отодвинуть более чем на один шаг. С отодвиганием ровно на один шаг справлялись операторы ++ и --. std::advance была выполнена именно в виде именованной функции (а не перегрузки операторов += или -=) именно для того, чтобы привлечь внимание пользователя к потенциально неэффективной операции и тем самым постараться исключить ее непреднамеренное использование. Аналогичные причины обусловили появление "парной" явной функции std::distance. std::next и std::prev - функции новые (С++11), созданные в частности для того, чтобы инкапсулировать идиому получения соседнего итератора без модификации текущего. Учитывая, что в общем случае к итератору не применима бинарная операция +, нельзя просто взять и прибавить к итератору 1 It it; ... foo(it + 1); // в общем случае - не сработает Для итераторов класс-типов в такой ситуации работает компактный вариант foo(++It(it)); но он неприменим к итераторам фундаментальных типов, что в generic контекстах заставляет заводить дополнительную именованную переменную, т.е. выписывать что-то вроде It it_next = it; foo(++it_next); Это более громоздко, чем хотелось бы, и вводит в код ненужную именованную переменную. Функция std::advance, если обратить внимание на особенности ее интерфейса, тут никак помочь нам не может. Вот тут-то и приходят на помощь функции std::next и std::prev, которые скрывают подобные детали. При этом их наиболее востребованным назначением/употреблением является именно получение соседнего итератора. А возможность указать расстояние - лишь естественное расширение этой функциональности. Другими словами, ответ на ваш вопрос в историческом ключе звучит просто: std::advance была создана именно для сдвига итератора более чем на 1 шаг, а std::next и std::prev заведены в первую очередь для сдвига ровно на 1 шаг. Также учитывая, что std::advance может работать в обоих направлениях, было бы странно сейчас навязывать ей именно +1 в качестве умолчательного аргумента. Вполне может быть, что если бы изначально в C++98 функцию std::advance ввели именно с интерфейсом template< class InputIt, class Distance > InputIt advance( InputIt it, Distance n ); (т.е. с передачей и возвратом итератора "по значению", а не с передачей модифицируемого итератора "по ссылке"), то сегодня особой необходимости в std::next и std::prev так и не возникло бы. А если бы эти функции и появились бы, то возможно без параметра "расстояния".

Ответ 3



Почему std::next дефолтно продвигает на 1, а std::advance - нет? Потому как std::next как и std::prev явно указывают направление модификации. И наличие дефолтного значения - лишь уточнение шага. Приписать же дефолтную модификацию для std::advance смысла нет, так как для данной функции позитивное и негативное смещения "равно-значимы". Если прописать шаг, то это автоматически приравнивается и к прописке дефолтного направления модификации, что не будет соответствовать аббревиатуре функции.

Как работает CancellationToken в TaskFactory.StartNew Method (Action, CancellationToken)?

#c_sharp #net #task


Делаю:

Task.Factory.StartNew(() =>Method(),ct)


В другом месте вызываю tokenSource.Cancel();, но ничего не происходит.

Мне казалось, что такая перегрузка должна полностью задачу снимать.

Получается, что нужно токен передавать непосредственно в сам метод и там производить
анализ?

Можно ли как-нибудь отменить задачу, непередавая во внутрь токен?
    


Ответы

Ответ 1



Смотрите. Вы не можете «отменить» уже бегущий код — по тем же причинам, по которым вы не можете «убить» бегущий thread. Поэтому код, запускаемый через Task.Run, добежит до конца, если только он сам не будет анализировать токен и не отменит себя сам. Однако, таск не будет запущен, если токен находится уже в отменённом состоянии. Поскольку запуск Task'а — расходная штука, это неплохая оптимизация. Кроме того, таск при этом будет ассоциирован с этим токеном, и если код в Method бросит исключение через token.ThrowIfCancellationRequested, это исключение будет считаться относящимся к таску. Тем самым таск будет завершён в состоянии Cancelled, а не Faulted. Источник информации: https://social.msdn.microsoft.com/Forums/en-US/c2f614f6-c96c-4821-84cc-050b21aaee45/taskfactorystartnew-cancellation-token-parameter?forum=parallelextensions Воспроизводящий пример: async Task Run() { var cts = new CancellationTokenSource(); var ct = cts.Token; var t = Task.Run((Action)(() => // каст нужен! пояснение в конце ответа { while (true) { ct.ThrowIfCancellationRequested(); Thread.Sleep(200); } }), cts.Token); await Task.Delay(400); cts.Cancel(); try { await t; } catch (TaskCanceledException ex) { Console.WriteLine($"caught TaskCanceledException, task status = {t.Status}"); } catch (OperationCanceledException ex) { Console.WriteLine($"caught OperationCanceledException, task status = {t.Status}"); } } Этот код попадает в catch (OperationCanceledException ex), и состояние таска — Canceled. А если убрать токен, то мы попадаем также в catch (OperationCanceledException ex), но состояние — Faulted. В этом случае рантайм считает, что произошла не отмена таска, а просто какое-то постороннее исключение. (В TaskCanceledException мы попадаем, если таск был отменён до запуска.) (Ошибка в предыдущей версии кода была в том, что не было явного приведения к Action [которое практически никогда не нужно!], и ввиду бесконечного цикла внутри типовыводитель не мог решить, это перегрузка с Action или перегрузка с Func! В результате он выбирал не то, что нужно, и рантайм считал, что отменён не таск, а процесс его создания.)

Ответ 2



Да, токен необходимо передавать в метод, и там периодически вызывать ThrowIfCancellationRequested(). Однако, это не отменяет необходимости передавать его вторым параметром StartNew(). Это делается на тот случай, если отмена операции запрошена раньше чем начал выполняться ваш метод (а так же для того, чтобы связать таск с токеном). Примерно так: var cts = new CancellationTokenSource(); Task.Factory.StartNew(() => { while (true) { cts.Token.ThrowIfCancellationRequested(); Console.WriteLine("I'm working..."); } }, cts.Token); cts.CancelAfter(10); Если была запрошена отмена, то метод ThrowIfCancellationRequested() кинет OperationCanceledException. При желании, его можно поймать и сообщить юзеру, что операция успешно отменена, например. Если хочется, то можно обходиться без эксепшена, а просто в методе проверять: if (token.IsCancellationRequested) { /*выходим из метода*/ } Но тогда сама задача не будет знать о том, что её отменили. В свойстве Status у неё будет TaskStatus.RanToCompletion вместо TaskStatus.Canceled. UPD: Дополнительный материал по теме: https://msdn.microsoft.com/en-us/library/dd997396(v=vs.110).aspx

Объясните этот синтаксис пожалуйста

#c #структуры


Нет, правда. Поверхностно я знаю C но это... новый синтаксис C99 наверное:

struct node {
    int payload;
    int height;
    struct node *kid[2];
} dummy = {0, 0, {&dummy, &dummy}}, *nnil = &dummy;
// internally, nnil is the new nul


Что вот это значит?:


Создать тип struct node node (оказывается имя типа всё-таки struct node) 
typedef struct node dumy Оказывается: объявить (глобальную?) переменную dummy содержащую
помимо прочего массив состоящий из двух указателей на саму себя
, => node* nnil = опять указатель на эту dummy


Я прав? Это шо за синтаксис такой? C99? (смайлик "я в ужасе")
    


Ответы

Ответ 1



struct node { Объявили структуру } dummy Создали переменную типа struct node = {0, 0, Первые два поля переменной dummy - нули (dummy.payload = dummy.height = 0) {&dummy, &dummy}} Элементам массива kid (указателям) присвоили адреса переменной dummy (dummy.kid[0] = dummy.kid[1] = &dummy) , *nnil Создали ещё одну переменную - указатель на переменную типа struct dummy = &dummy; Присвоили ей адрес переменной dummy Всё, никаких хитростей, чистый C безо всяких наворотов.

Ответ 2



В этой конструкции сразу же объявляется структура, объект этой структуры и указатель на объект этой структуры. Чтобы это объявление struct node { int payload; int height; struct node *kid[2]; } dummy = {0, 0, {&dummy, &dummy}}, *nnil = &dummy; было более понятным, вы можете его разбить на несколько объявлений. Исходное объявление эквивалентно следующим объявлениям. struct node { int payload; int height; struct node *kid[2]; }; struct node dummy = {0, 0, {&dummy, &dummy}}; struct node *nnil = &dummy; То есть объявляется структура с именем struct node. Затем объявляется объект этой структуры с именем dummy и его поля, как объекта структуры, инициализируются соответствующими значениями. Чтобы это объявление было еще более понятным, вы можете даже его переписать в C99 как struct node dummy = { .payload = 0, .height = 0, .kid = { [0] = &dummy, [1] = &dummy }}; В этом объявлении объекта dummy его член данных kid, который представляет собой массив указателей, инициализируется адресом самого объекта dummy. И, наконец, в третьем объявлении объявляется указатель с именем nnil на объект dummy

Как отличить текст в файле с обычной кодировкой от Unicode?

#cpp #windows #unicode #текст


Нужно прочесть текстовый файл. Как узнать, закодирован таблицей символов (однобайтовых),
или в файле содержится текст в формате Unicode (16-ти битные символы)?
    


Ответы

Ответ 1



Файл всегда содержит байты. Иногда содержимое файла можно декодировать в текст, используя выбранную кодировку такую как cp1251, cp866, utf-8, или utf-16le. На Windows, файлы, закодированные в utf-16, к сожалению иногда называют Unicode (что вводит в заблуждение: Unicode—это не кодировка). utf-16 это всего лишь одна из многих кодировок, которую можно использовать, чтобы закодировать текст (Unicode) в байты: байты = юникод_текст.encode(кодировка) юникод_текст = байты.decode(кодировка) Файлы, содержащие текст, закодированный в utf-8, utf-16, utf-32 и других кодировках, могут содержать в начале специальную последовательность байт (U+FEFF символ BOM, закодированный в соответствующей кодировке), которая идентифицирует эти кодировки. Если файл следует этому соглашению, то достаточно несколько первых байт из файла (в двоичном режиме открытого) сравнить с вариантами BOM, чтобы определить соответствующую кодировку. В общем случае нет гарантированного на 100% способа определить кодировку файла (хотя некоторые кодировки могут быть более вероятны чем другие и может быть API, которое пытается угадать кодировку, такое как: IsTextUnicode() с IS_TEXT_UNICODE_STATISTICS). Пример: "Bush hid the facts" текст, закодированный в ascii кодировке, мог некоторыми приложениями интерпретироваться как текст в utf-16le кодировке, приводя к кракозябрам.

Ответ 2



Зависит от соглашения, в котором записан текстовый файл. Текстовый поток, записанный в формате Unicode может начитаться с BOM - Byte Order Mark, т.е. например с магических байтов FF, FE для UTF-16 Little Endian. А в отсутствие каких-либо соглашений - только анализ текста с элементами гадания на кофейной гуще.

Ответ 3



Простая на первый взгляд задача, но выполнить её оказывается не просто. С++ обладает достаточной гибкостью, как язык среднего уровня, поэтому требуется исчерпывающее знание вопроса для эффективной реализации задачи. Поделюсь тем что выяснил.Чтобы правильно прочесть файл нужно сначала посмотреть, есть ли в начале файла Маркер последовательности (тут точнее). Если есть маркер, его нужно определить. Если маркера нет, как выше уже было сказано, нужно искать другой алгоритм определения кодировки.Я тут целиком и полностью полагаюсь на IsTextUnicode, если маркера нет:BYTE *pBuf;size_t szRead, szBOM; // к-во прочитанных в файле байт и к-во байт маркераenum Unicode eUnicode;LPTSTR pszText;...// определяю, есть ли в тексте маркер (ручная работа)szBOM = IsUnicodeRaw(pBuf, szRead, &eUnicode);// вызов библиотечной ф-ции IsTextUnicode после собственной проверкиif(eUnicode != utf_16LE && ((szRead - szBOM) % 2 || !IsTextUnicode(pBuf + szBOM, (int) (szRead - szBOM), NULL))){ BYTE *pb = new BYTE[(szRead - szBOM + 1) * sizeof(wchar_t)]; unsigned int nCP = (eUnicode == utf_8) ? CP_UTF8 : (eUnicode == utf_7) ? CP_UTF7 : CP_ACP; if (!MultiByteToWideChar(nCP, (nCP == CP_ACP) ? MB_PRECOMPOSED : 0, (LPCSTR) (pBuf + szBOM), (int) (szRead - szBOM), (LPWSTR) pb, (int) (szRead - szBOM))) { // ошибка... } delete[] pBuf; pszText = (LPTSTR) (pszBuf = pb)}else pszText = (LPTSTR) (pszBuf + szBOM);После того как выяснил наличие маркера в ф-ции IsUnicodeRaw, обращаюсь к IsTextUnicode без маркера. Работает с UTF-8, с UTF-7 нужно разбираться - там последние 2 бита маркера являются частью следующего за маркером символа. ANSI-текст так же нормально кодирует в двухбайтовый.Wind'а предпочитает UTF-8 и UTF-16LE. Перед тем как записать текст, его нужно либо перекодировать в ANSI ф-цией WideCharToMultibyte, либо в начало файла записать маркер кодировки UTF-8 или UTF-16LE, чтобы потом также прочесть.

Ответ 4



Кажется, нашёл. Ф-ция IsTextUnicode из Advapi32.dll ответит на поставленный вопрос.

Какие стили лучше задавать по умолчанию?

#css #вёрстка


При просмотре туториалов, связанных с версткой заметил, что часто перед началом работы,
авторы задают какие-то стили по умолчанию, переопределяют дефолтные стили браузера.
Собственно, возникло пару вопросов по этому поводу:


Зачем это делается?
Стили каких элементов лучше переопределить в самом начале?
Где можно об этом почитать поподробнее и найти код? Гуггл мне не очень помог, каюсь,
может плохо гугглил.

    


Ответы

Ответ 1



Зачем это делается? По умолчанию, в браузерах есть встроенные определения для HTML-элементов. Например, у и

есть margin, у

    и
      есть padding и list-style, ну и так далее. В каждом браузере эти предустановленные значения могут быть разными, соответственно, normalize.css или reset.css нужны для того, чтобы стартовать с одинаковой базы. Различие их состоит в том, что normalize.css приводит все элементы к одинаковому стилю, а reset.css сбрасывает всё полностью в ноль. Лично мне больше нравится использовать reset.css, потому что, как правило, все элементы потом всё равно переопределяются и для каждого проекта формируется некое подобие UI kit. Но если вы верстаете страницу без формирования определения всех элементов, то, возможно, вам подойдет normalize.css — так вам не надо будет задавать отступы между параграфами и заголовками, переопределять списки и т. д. Стили каких элементов лучше переопределить в самом начале? Тут всё упирается в то, какую стратегию вы выбрали :) Мой необходимый набор: *, *:after, *:before { box-sizing: border-box; margin: 0; padding: 0; } Где можно об этом почитать поподробнее и найти код? Хорошая статья на HTML-академии и на Хабре. Код: reset.css, normalize.css. P.S. reset будущего будет выглядеть примерно так: * { all: unset; } head { display: none; }

      Ответ 2



      Есть два основных подхода - reset.css и normalize.css. Остальное - в google.com

      Ответ 3



      html, body { margin: 0; padding: 0; } Остальное - ручки)

      Ответ 4



      Делается для того, чтобы у всех браузеров привести дефолтные стили к какому-то номиналу, и получить более ожидаемое поведение от элементов на странице и не было всевозможных "призрачных" отступов в каком-нибудь фаерфоксе, и корректного отображения в хроме(например). Переопределяются в основном ссылки, списки, отступы внутренние и внешние у body, div'a, поля ввода, по большому счету, все, что используется в проекте, по хорошему необходимо "обнулить". Гугли всевозможные reset.css. Например, как можно видеть на скрине, в разных браузерах стили рендерятся по разному. В данном случае, FF добавил отступ перед тэгом p. Во избежание таких случаев и применяются сбросы стилей. Немного советов: Сброс стилей - отдельным файлом, включаемым в документ в самом начале. Лучше индивидуальным элементам расписывать сбросы стилей отдельно, дабы достичь максимального контроля над внешним видом страницы. Из минусов - разве что, что-нибудь забыть. Сброс не обязательно приводить к нулевым значениям, можно сразу указать те, что по дефолту будут использоваться в Вашем проекте. Написанное выше является выдержкой из статьи с хабра, отсюда, .

      Ответ 5



      Используйте normalize.css популярная и проверенная библиотека для нормализации стилей в разных браузерах. А дальше используйте сброс(задавать по умолчанию) стилей по вашему вкусу.

Как печатать каждый n-ый элемент массива в ruby?

#ruby


Как печатать каждый n-ый элемент массива в ruby?
    


Ответы

Ответ 1



Например, вот так: arr = [1, 2, 3, 4, 5, 6] n = 3 for i in (n-1..arr.length - 1).step(n) puts arr[i] end Или же так: (n-1..arr.length - 1).step(n) do |i| puts arr[i] end Или ещё компактнее: (n-1..arr.length - 1).step(n) { |i| puts arr[i] } Вывод: 3 6

Ответ 2



Например так: n = 5 (1..40).step(n) {|y| puts y} Будет печатать каждый 5-й элемент, начиная с 1-го.

Ответ 3



В функциональном стиле... Возьму вот эти данные для примера: a = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] n = 2 # каждый 2-й (n-1...a.length).step(n) .map(&a.method(:[])) .each(&method(:puts)) # 9 # 7 # 5 # 3 # 1 n-1...a.length это интересующий нас диапазон индексов, первый из которых обозначает первый элемент интересующего нас результата. Заметьте, что точек три, а значит указанная правая граница в него не входит. В конце концов, a[a.length] всегда nil. (n-1...a.length).step(n) пропускает все индексы из диапазона, кроме каждого n-го. Остаются только те, что нужны. Осталось найти способ преобразовать коллекцию индексов в коллекцию элементов. Есть у рубистов известный трюк с Symbol#to_proc: если всё, что должен делать блок, это вызвать у переданного в него объекта какой-то метод, то вместо написания этого блока руками можно передать в аргументы &:метод в качестве блока. (1..2).map { |i| i.to_s } (1..2).map(&:to_s) # <= то же самое Но здесь этот трюк не работает, поскольку метод надо вызвать не у переданного объекта. Нужен другой трюк. Чуть менее известный. Тут-то и можно воспользоваться method'ом: он возвращает Proc-совместимые объекты методов, всё ещё привязанных к своим владельцам. Амперсанд (&) при вызове метода работает со всем, что имеет метод to_proc). С помощью .map(&a.method(:[])) коллекция индексов преобразуется в коллекцию значений из a по этим индексам. А с помощью .each(&method(:puts)) эта коллекция выводится на экран. На самом деле, решение совершенно непрактичное, но показывает не самые известные детали языка.

Ответ 4



[1,2,3,4,5,6].each_with_index {|val, index| puts val if index % 2 == 0}

Как задать ограничения на параметры шаблонных классов?

#cpp #шаблоны_с++


Есть абстрактный класс M и классы A, B и C, для которых М - родительский класс, и
в них реализованы все абстрактные методы класса М.
Нужно создать шаблонный класс

template  class S{ ... };


в котором качестве шаблона используются классы A, B или C.
Можно как-то указать, что M должен быть родительским классом для Т?
    


Ответы

Ответ 1



Вас спасет std::is_base_of: struct M {}; struct A: public M {}; struct B {}; template::value>> struct S {}; int main(int argc, const char * argv[]) { S a; S b; }

Ответ 2



Один из способов - это просто объявить, например, typedef для базового класса шаблонного параметра внутри шаблонного класса. Если шаблонный параметр не имеет такого базового класса, то будет выдано сообщение об ошибке. Например, #include class M { virtual void f() const = 0; }; class A : public M { virtual void f() const { std::cout << "A" << std::endl; } }; class B { }; template class S { typedef typename T::M Base; }; int main() { S
s1; // S s2; return 0; } Если раскомментировать в этой программе закомментированное предложение, то компилятор выдаст сообщение об ошибке.

Ответ 3



А если у вас старый компилятор, то можно пойти длинным путем: class M { virtual void f() const = 0; }; class A : public M { virtual void f() const { std::cout << "A" << std::endl; } }; class B { }; template class IsDerivedFrom { class No {}; class Yes { No no[2]; }; static Yes Test(B*); static No Test(...); public: enum { Is = sizeof(Test(static_cast(0))) == sizeof(Yes) }; }; template ::Is> class S { }; template class S { S() { char * p = (int*)0; } }; int main() { S
s1; S s2; return 0; } Зато работает на старых компиляторах, которые не знают C++ 11.

Ответ 4



Можно использовать std::is_base_of: #include #include class M { public: virtual void f() = 0; }; class A: public M { public: virtual void f() { std::cout << "class a\n"; } }; class B { public: virtual void f() { std::cout << "class b\n"; } }; template::value>::type> class S { public: T t; void f() { this->t.f(); } }; int main() { S
a; //S b; return 0; } Если раскомментировать S b, то выдастся ошибка при компиляции.

странный синтаксис

#cpp #массивы #указатели #cpp11


очень неясно как работает данный код

int a[] = {4, 5, 2, 3, 1};
int i = *a;

for (;i;)
{
    std::cout << i--[a];  // не понятная строчка
}

//  output: 1325


к чему тут декремент применяется??? 

ну, очевидно, что к переменной i, раз цикл завершается.

Но как тогда происходят обращения к элементам массива ? почему нет ошибки компиляции ?

Впервый раз в жизни встречаю подобный код
    


Ответы

Ответ 1



Декремент тут применяется i хотя бы просто потому, что больше он в данной записи ни к чему применяться не может - справа от него стоит лексема [, которая началом выражения-операнда быть никак не может. Тема же эквивалентности a[i] и i[a] заезжена донельзя. Выражение x[y] по определению является лишь сокращенной формой записи для *(x + y). Один операнд должен быть массивом/указателем, а другой - целочисленным или enum значением. Причем ограничений на порядок указания операндов не накладывается. Поэтому ваше i--[a] эквивалентно *(i-- + a) эквивалентно *(a + i--) и эквивалентно a[i--]. Никакой "ошибки компиляции" тут нет. Вышесказанное относится именно и только к встроенному оператору []. Для перегруженного оператора [] порядок аргументов фиксирован, то есть для выражения x[y] будет рассматриваться только перегруженный вариант x.operator[](y), но не y.operator[](x).

Ответ 2



Оператор индексирования относится к классу постфиксных операторов. Он определяется следующим образом (стандарт C++, раздел 5.2.1 Subscripting) 1 A postfix expression followed by an expression in square brackets is a postfix expression. То есть за постфиксным выражением следует выражение в квадратных скобках. В этом выражении i--[a] i-- - это оператор пост-декремента, который относится к классу постфиксных выражений. Итак, имеется i-- [a] | | постфиксное выражение выражение в квадратных скобках Так что с точки зрения синтаксиса данное выражение совершенно корректное. Далее в той же самой цитате из стандарта имеется продолжение 1 ... One of the expressions shall have the type “array of T” or “pointer to T” and the other shall have unscoped enumeration or integral type. The result is of type “T.” The type “T” shall be a completely-defined object type.64 The expression E1[E2] is identical (by definition) to *((E1)+(E2)) из которого следует, что одно из выражений должно быть либо массивом, либо указателем, а другое выражение - перечислением или целочисленным типом. Какое из этих двух выражений какой должен иметь тип не существенно, так как по определению выражение E1[E2] эквивалентно выражению *((E1) + (E2)). В С++ вы можете написать даже более вычурную конструкцию, добавив знак плюс перед именем массива. Например, #include int main() { int a[] = { 0, 2, 4, 6, 8 }; int i = 0; std::cout << i++[+a] << std::endl; return 0; } В C такая конструкция i++[+a] не будет компилироваться, так как в C в отличии от C++ нельзя применять унарный плюс к имени массива. В C++ пользователь также может перегружать оператор индексирования для списка инициализации в фигурных скобках. Например, #include #include #include int main() { struct A { long long int operator []( std::initializer_list l ) const { return std::accumulate( l.begin(), l.end(), 0ll ); } }; std::cout << A()[{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }] << std::endl; return 0; } Вывод программы на консоль 55

Как начать делать текстовый квест?

#c_sharp


Нужно реализовать класс Quest в котором будут хранятся шаги.

Шаги представляют собой класс с каким-то текстом и вариантами выбора. Пользователь
сам добавляет шаги и варианты выбора, которые в свою очереди ведут к следующим шагам
(сценам) в зависимости от выбора игрока. Как я понимаю каждый выбор должен иметь ссылку
на следующий шаг (сцену). Но как это реализовать в коде не понимаю.
    


Ответы

Ответ 1



В общем, @VladD абсолютно прав, вам нужен конечный автомат (в английской терминологии state machine), и желательно разобраться что это такое подробнее, но я попробую показать простой для понимания пример не используя пока специфическую терминологию. Вам попадались книги-игры Дмитрия Браславского? В прочем если бы попадались, вопрос бы не возник. И так, что такое текстовый квест? Это набор параграфов, описывающих некоторые игровые сцены в которых игроку требуется принять некоторое решение, чтобы перейти к другой сцене. Ок, от этого и пойдем. Пронумеруем все параграфы в произвольном порядке. Для книги нумерация имеет значение, для компьютерного варианта - нет. Размещаем параграфы в массив согласно сделанной нумерации. Каждый выбор игрока, фактически, означает выбор следующего параграфа, но выбор в слепую, т.к. игрок не знает содержимое параграфа (во всяком случае в первой игре). Таким образом, необходимо сопоставить предлагаемые игроку действия на текущей сцене с номерами параграфов на который они ведут. Когда игрок сделал свой выбор, мы просто показываем ему текст следующего параграфа с соответствующим индексом в массиве и ожидаем следующего выбора игрока, разумеется если это выбор у него есть в данной сцене. Естественно возможен вариант, когда игрок может попасть на одну и туже сцену (параграф) разными путями. Таким образом, вам достаточно одного единственного класса для описания модели вашего квеста, при этом ни чего мудреного не требуется. Для консольного варианта достаточно базовых знаний C#: синтаксис, условия, массивы, циклы. ну и немного стандартных классов для организации ввода/вывода. В эту модель прекрасно вписывается и "боевка" с бросанием кубиков, и применение ранее приобретенных вещей, если сцена предполагает возможность их применения. Какую к данной модели приделать "шкурку": консоль, или развесистый графический интерфейс с иллюстрациями и музыкой, не имеет значения, т.к. самое сложное в данном типе игр - создать сюжет и написать тексты игровых сцен, чтобы они не были все на одно лицо. Единственное что я бы посоветовал лично от себя - не показывайте игроку настоящие номера параграфов, спрячьте их за кнопками с текстом, локальными номерами (1,2,3 и т.д. по количеству вариантов выбора в сцене) для консоли, ссылками для Web-версии. Так интереснее, и больше вероятность, что игрок хотя бы прочитает (а может и запомнит) текст над которым вы или ваш сценарист трудились, создавая квест. Ну и немного кода для иллюстрации возможной (но не единственной) реализации такой модели: Простейший вариант для консоли с одним классом: class Quest { public string[] Paragraphs {get; set;} public int[][] Choises {get; set;} //Для консольного варианта вы просто отображаете номера для выбора прямо в тексте //параграфа, рядом с описанием выбора, как в книжном варианте. } Более сложный пример: class Paragraph //параграф (игровая сцена) { public int Num {get; set;}//не особо нужен, но для полной картины пусть будет public string Text {get; set;} //доступные варианты, список может быть нулевой длины, но не null. public List Choises {get;} = new List(); } class Choise { public int NextParagraph {get; set;} public string Text {get; set;} //текст варианта выбора для игрока } class Quest { Paragraph Current {get; set;} //Если номера параграфов соответствуют индексам можно так List {get;} = new List(); //Если лень следить за соответствием - так Dictionary {get;} = new Dictionary(); } Если знаете что такое направленный граф, то можно еще проще class Paragraph //параграф (игровая сцена) { public string Text {get; set;} //текст параграфа //доступные варианты, список может быть нулевой длины, но не null. public List Choises {get;} = new List(); } class Choise { public Paragraph Next {get; set;} public string Text {get; set;} //текст варианта выбора для игрока } class Quest { Paragraph Current {get; set;} Paragraph StartPoint {get; set;}; } С кодом ввода выбора игрока и вывода текста на экран, думаю сами справитесь.

непонятное поведение аргумента функции

#cpp


когда вызываю функцию прямо в ostream, не получаю нужный результат, а когда вызываю
до cout, то все нормально...

#include 
#include 
using std::string;

string pop_word(const char*& p)
{
    const char* q = p;
    size_t count = strlen(q);
    string s = p;
    while (!isdigit(*q) && --count > 0) ++q;
    string str = s.substr(0, q - p);
    while (*q == ' ' && --count > 0) ++q;
    if (*q) p = q;
    return str;
}

int main()
{     
    const char* p = "unsigned  45678";
    const char* q = p;

    string s = pop_word(p);
    std::cout << s  << '\n' << p << '\n';
    // p указывает на "45678" (все нормально)

    std::cout <


Ответы

Ответ 1



Наблюдаемое вами поведение вызвано тем, что ваш компилятор не удовлетворяет требованиям С++17 или работает в до-C++17 режиме. До С++17 порядок вычисления аргументов в выражении std::cout << pop_word(q) << '\n' << q; был не специфицирован. Компилятор имел право сначала вычислить (подготовить, передать) аргумент q, а затем вычислить аргумент pop_word(q). А мог поступить и наоборот. Так как pop_word(q) изменяет значение q, результат отличался бы в этих случаях. Но начиная с С++17 левый операнд <<, как для встроенного, так и для перегруженного оператора, должен вычисляться до того, как вычисляется правый (спасибо @wololo за подсказку). Это означает, что в данном выражении вывод однозначен unsigned 45678 P.S. Что интересно, GCC в режиме -std=c++17 -Wsequence-point все равно продолжает предупреждать о неопределенном поведении в int i = 0; std::cout << ++i << ++i << ++i << std::endl; хотя в С++17 никакого неопределенного поведения тут не должно быть.

Ответ 2



В каком порядке будут вычислены операнды неизвестно. В Вашем случае, сначала запоминается значение q, и только потом выполняется pop_word. Выведите q в следующем statement'е, думаю, там всё нормально. std::cout <

Python Взаимодействие с cmd.exe

#python #windows #python_3x #cmd #subprocess


Добрый день.
С питоном знаком не так давно.
Уже не первый день бьюсь с такой задачей:
Необходимо вызвать командную стоку windows,  отправить команду (например ipconfig)
Затем полученный результат сохранить в notepad.
Пробовал через pywinauto/ subprocess, к сожалению дальше вывода cmd экран продвинуться
не смог.
Подскажите, как можно реализовать, или в каком направлении искать :-) 
Заранее спасибо.
    


Ответы

Ответ 1



Чтобы получить результат команды как строку, не обязательно cmd.exe вызывать, можно напрямую запустить дочерний процесс: import subprocess output = subprocess.check_output('ipconfig') Чтобы "сохранить в notepad", просто в файл пишите результат: from pathlib import Path Path('~/output.txt').expanduser().write_bytes(output) Вместо приведённого пути (сохраняет файл output.txt в домашнюю директорию пользователя), можно специфичную для программы директорию использовать (текущую рабочую директорию или путь относительно скрипта или что appdirs модуль возвращает). Можно за один шаг: вызывать команду и сохранить её результат в файл сразу: with Path('~/output.txt').expanduser().open('wb', 0) as file: subprocess.run('ipconfig', stdout=file, check=True) См. Python - Запуск cmd.exe с аргументом, и последующим сохранением ответа в .txt файл Чтобы сохранить вывод, используя другую кодировку (к примеру, если вы кракозябры видите), необходимо декодировать вывод программы в Unicode, а затем сохранить в кодировке, которую понимает ваше окружение: import ctypes import os encoding = os.device_encoding(1) or ctypes.windll.kernel32.GetOEMCP() text = subprocess.check_output('ipconfig', encoding=encoding) Byte при печати вывода внешней команды. После этого в желаемой кодировке можно сохранить. К примеру, по умолчанию используется locale.getpreferredencoding(False) кодировка: Path('~/output.txt').expanduser().write_text(text) вы можете в write_text() другую кодировку передать (к примеру, encoding='utf-8').

Ответ 2



os.system("ipconfig >some-file.txt")

Ответ 3



Большое спасибо за помощь. Получившийся работающий код: def ipconf_cmd(): text = subprocess.check_output('ipconfig') decoded = text.decode('cp866') Path('~/output.txt').expanduser().write_text(decoded)