Страницы

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

пятница, 13 декабря 2019 г.

Программное получение строки по ее имени в файле ресурсов

#java #android #строки


Приветствую, такой вопрос, у меня есть 50 значений строк c именами name1, name2,
и т.д и разным текстом, хранятся в файле String.xml. Сначала в textView показывается
1 строка с именем name1, по нажатию кнопки, textView показывает name2, и т.д. Сейчас
это сделано примитивным способом:
Есть переменная Count, при нажатии кнопки Count увеличивается на 1 и сравнивается
значение

 switch (Count) {
                    case 1:
                         textView.setText(R.string.name1);
                        break;
                    case 2:
                         textView.setText(R.string.nаme2);
                        break;
                     ...............


Но так как значений 50, это делать глупо.

Можно ли организовать что-то типа такого:
textView.setText(R.string.nаme+count);     ?

Или есть решение попроще?
    


Ответы

Ответ 1



Храни свои 50 строк в массиве строк strings.xml, в виде Mercury Venus Earth Mars Обращение к массиву в коде производится вызовом метода getResources().getStringArray(R.array.your_array); который возвращает массив строк

Ответ 2



Прописывать нужные строки в коде и хранить их в памяти не самый лучший вариант. Вы можете получить содержимое любого ресурса по его имени,в том числе сформированного динамически, через метод getIdentifier() SDK, для которого в качестве параметров необходимо указать: само имя ресурса, тип ресурса (string, dimen, color, drawable, id и тд.), имя пакета. Например, чтобы получить строковый ресурс с именем name1: package com.example.myapp; ... int stringNumber = 1; int stringID = getResources().getIdentifier("name" + stringNumber, "string", "com.example.myapp"); TextView text = (TextView)findViewById(R.id.text); text.setText(stringID); names.xml String number 1 String number 2 В TextView будет выведено: "String number 1" Стоит заметить, что вы можете поместить свои строки не в strings.xml, а в отдельный файл, какой-нибудь names.xml, как в моем примере, с аналогичной структурой и поместить этот файл в папку res/values/, чтобы не хранить их вместе с строковыми ресурсами самого приложения и удобнее было редактировать. PS: у вас будет свое имя пакета, указанное после оператора package а не com.example.myapp Альтернативным решением может быть парсинг JSON или XML, SDK предоставляет инструменты для этого.

Ответ 3



Альтернативное решение Как я уже отметил в комментарии, хранить одновременно все 50 строк в памяти может быть неэффективно, да и код переписывать при появлении новых строк - неправильно. Решение должно быть таким, чтобы при добавлении и изменении строк не приходилось переписывать код. Поэтому предлагаю хранить строки в текстовом файле и написать метод, который загружает строку по ее номеру. Тогда все 50 переменных вообще исчезают из вашего кода и памяти приложения, а остается textView.setText(loadString(i)); Прямое решение Положите строки в массив или список и обращайтесь к ним по индексу. Вот на английском SO я об этом отвечал: https://stackoverflow.com/a/30864495/2790048 Напрямую обращаться к переменной, имея строку с ее именем, нельзя. Это возможно с помощью пакета Reflexion, но это непроизводительно и чревато ошибками, да и не требуется в данном случае. Можно добавить все строки или объекты любого другого класса в параметризованный список: int initialCapacity = 50; List stringsList = new ArrayList(initialCapacity); for (int i = 0; i < 10; i++) { stringsList.add(loadString(i)); } Если количество совершенно точно не меняется в ходе работы программы, можно использовать массив: String[] stringsArray = new String[10]; for (int i = 0; i < lists.length; i ++) { stringsArray[i] = loadString(i); } Теперь к ним удобно обращаться: textView.setText(stringsList.get(i)); textView.setText(stringsArray[i]);

Ответ 4



Для этого можно использовать Reflection, чтобы найти значение свойства R.string динамическим образом. try { String text = (String) R.string.class.getField("name" + count).get(null); textView.setText(text); } catch (Exception e) { // R.string.name{count} либо не существует, либо не является строком. } Как @Nick Volynkin отметил в коментарии, есть большая вероятность, что другое решение существует лучше хранения 50 строк в strings.xml. Если возможно, лучше найти способ кроме Reflection, потому что Reflection выполняется медленно и иногда может быть немного опасным. Но я не знаю детали о вашем проекте, так что не знаю, что ещё рекомендовать вам.

Ответ 5



getResources().getString(R.string.MyString) Это для отдельной строки, но если вы задали Массив в XML файле, то можно вызвать его getResources().getStringArray(R.string.MyArrayString)

Замена дефолтного редактора кода в git

#git #редактор #git_config


Начал работать с git (а именно c BitBucket) и встроенный редактор (VIM) оказался
для меня весьма непонятным в управлении.

Возникло желание заменить его на другой (хоть на встроенный в OS Windows 7 блокнот).
Как это сделать?
    


Ответы

Ответ 1



1. Уровни настройки. Редактор, который использует Git, выбирается из следующего списка, именно в этом порядке (из man git-commit): Значение переменной окружения GIT_EDITOR Значение в конфигурации Git core.editor. Используется обычный для Git приоритет настроек: --local — для данного проекта. --global — для данного пользователя. Логично настраивать редактор именно на этом уровне. --system — для этой рабочей машины (в рамках ОС). Значение переменной окружения VISUAL Значение переменной окружения EDITOR (зачем столько переменных?) Если все эти варианты не установлены, то использует Vi/Vim. 2. Зачем -w? Зачем в большинстве приведенных команд параметр -w (--wait)? Git открывает редактор и ждет возврата exit code, чтобы продолжить работу на основе данных в файле. Если этого параметра нет, Git будет продолжать работу сразу и не дождется, когда вы отредактируете и сохраните файл. из atom -h: -w, --wait Wait for window to be closed before returning. 3. Настройка через изменение core.editor. Не требует прямого редактирования файлов и обладает гибкостью в уровнях настройки. Минус в том, что остальные приложения продолжат использовать редактор по умолчанию. В общем виде настройка конфигурации выглядит так: git config --global core.editor "editor --parameters" 3.1 Linux, OS X Многие редакторы (Atom, TextWrangler и другие) не включают поддержку командной строки при установке. Их необходимо включить отдельно, найдя в меню команду Install Shell Commands. Эти строки можно сразу копировать и выполнять в терминале: Atom: git config --global core.editor "atom -w" Emacs (-w по умолчанию): git config --global core.editor "emacs" Sublime Text git config --global core.editor "subl -n -w" Textmate git config --global core.editor "mate -w" TextWrangler git config --global core.editor "edit -w" Vim (-w по умолчанию): git config --global core.editor "vim" 3.2 Windows Вариант 1: добавить редактор в переменную PATH и использовать строки как для *nix. Некоторые редакторы при установке сами прописывают себя в PATH. Вариант 2: не меняя переменную PATH, напрямую указать путь к исполняемому файлу. Обратите внимание на вложенность кавычек и на то, как лаконично выглядит параметр --wait под Windows. Notepad++, на 32-битной ОС (источник): git config --global core.editor \ "'C:/Program Files/Notepad++/notepad++.exe' -multiInst -notabbar -nosession -noPlugin" Notepad++, на 64-битной ОС: git config --global core.editor \ "'C:/Program Files (x86)/Notepad++/notepad++.exe' -multiInst -notabbar -nosession -noPlugin"

Ответ 2



В гите есть настройка для редактора, можно сделать например так git config --global core.editor youreditor Переменная youreditor должна быть прописана в PATH. Когда Вы набираете в виндовой консоли youreditor, то консоль лезет в PATH и смотрит, какой файл соответствует собственно youreditor. Однако менять его стоит на что-то продвинутое, с обычным блокнотом Вы гарантированно получите немало проблем, в частности с окончаниями строк.

Ответ 3



Очень удобный редактор git средах от JetBrains (PHPStorm, WebStorm, RubyMine, IDEA) Алгоритм добавления git репозитория: VCS -> Enable VCI git add ./ Создаем на BitBucket новый репозиторий Прописываем в настройках терминала phpstom "C:\Program Files (x86)\Git\bin\sh.exe" --login -i - в случае windows, /bin/bash - в случае linux Пишем в консоли git remote add origin https://ASDAlexey@bitbucket.org/ASDAlexey/angular-multi-select.git

Маппинг классов в C# по имени свойств?

#c_sharp #linq


Как на C# или через LINQ сделать такое:

class A
{
    public string First { get; set; }
    public string Second { get; set; }
    //...
    //другие свойства
};

class B
{
    public string Third { get; set; }
    public string Four { get; set; }
    //...
    //другие свойства
};

class Result
{
    public string First { get; set; }
    public string Second { get; set; }
    public string Third { get; set; }
    public string Four { get; set; }

    //...
    //другие свойства
};


Как примапить A & B к Result?

Можно конечно написать вручную:

r.First = a.First;
r.Second = a.Second;
r.Third = b.Third;
r.Four = b.Four;


Но так слишком много писать, хотелось бы по короче и побыстрее.
    


Ответы

Ответ 1



Ответы-ссылки тут не приветствуются, но в этом случае без ссылки никак: AutoMapper. Package Manager: Install-Package AutoMapper C#: Mapper.CreateMap(); Mapper.CreateMap(); var a = new A() { First = "1", Second = "2" }; var b = new B() { Third = "3", Four = "4" }; var res = Mapper.Map(a); Mapper.Map(b, res); // 1, 2, 3, 4 или с динамическим маппингом: var a = new A() { First = "1", Second = "2" }; var b = new B() { Third = "3", Four = "4" }; var res = Mapper.DynamicMap(a); Mapper.DynamicMap(b, res);

Ответ 2



В таких случаях обычно используют рефлексию. Простой пример копирования публичных свойств с идентичными типами: static TTarget Copy(object source) where TTarget : new() { if (source == null) return default(TTarget); const BindingFlags publicInstance = BindingFlags.Public | BindingFlags.Instance; var result = new TTarget(); var targetType = typeof(TTarget); var sourceProperties = source.GetType().GetProperties(publicInstance); foreach (var sourceProperty in sourceProperties) { if (sourceProperty.CanRead) { var targetProperty = targetType.GetProperty(sourceProperty.Name, publicInstance); if (targetProperty != null && sourceProperty.PropertyType == targetProperty.PropertyType) targetProperty.SetValue(sourceProperty.GetValue(source), result); } } return result; } Проблема в таких мапперах заключается в том, что они требуют серьёзного тестирования для разнообразных граничных случаев и нетривиальных преобразований типа. В качестве работающей альтернативы действительно хорошо подходит автомаппер, который уже хорошо протестирован.

Ответ 3



Вот тот же пример для .NET 4 static TTarget Copy(object source) where TTarget : new() { if (source == null) return default(TTarget); const BindingFlags publicInstance = BindingFlags.Public | BindingFlags.Instance; TTarget result = new TTarget(); Type targetType = typeof(TTarget); PropertyInfo[] sourceProperties = source.GetType().GetProperties(publicInstance); foreach (PropertyInfo sourceProperty in sourceProperties) { if (sourceProperty.CanRead) { PropertyInfo targetProperty = targetType.GetProperty(sourceProperty.Name, publicInstance); if (targetProperty != null && sourceProperty.PropertyType == targetProperty.PropertyType) { object[] myArgs = new object[1] { sourceProperty.GetGetMethod().Invoke(source, null) }; targetProperty.GetSetMethod().Invoke(result, myArgs); } } } return result; }

Ответ 4



Вот доработанная версия для .NET 4, теперь копируются и подклассы и конвертируются массивы. Код конечно очень плохо написан. private class MDS_Tools { public static TTarget Copy(object source) where TTarget : new() { if (source == null) return default(TTarget); const BindingFlags publicInstance = BindingFlags.Public | BindingFlags.Instance; TTarget result = new TTarget(); Type targetType = typeof(TTarget); PropertyInfo[] sourceProperties = source.GetType().GetProperties(publicInstance); foreach (PropertyInfo sourceProperty in sourceProperties) { if (sourceProperty.CanRead) { PropertyInfo targetProperty = targetType.GetProperty(sourceProperty.Name, publicInstance); if (targetProperty != null) { MethodInfo smi = sourceProperty.GetGetMethod(); if (sourceProperty.PropertyType == targetProperty.PropertyType) { object[] myArgs = new object[1] { smi.Invoke(source, null) }; targetProperty.GetSetMethod().Invoke(result, myArgs); } else { if (smi.ReturnType.GetInterfaces().Where(t => t.Name == "IEnumerable").FirstOrDefault() != null) { object arrToCopy = Activator.CreateInstance(targetProperty.GetGetMethod().ReturnType); MethodInfo addMeth = arrToCopy.GetType().GetMethod("Add"); IEnumerable enAr = (IEnumerable)smi.Invoke(source, null); if (enAr != null) { foreach (var s in (IEnumerable)smi.Invoke(source, null)) { addMeth.Invoke(arrToCopy, new object[1] { typeof(MDS_Tools).GetMethod("Copy").MakeGenericMethod(((IEnumerable)arrToCopy).AsQueryable().ElementType).Invoke(null, new object[] { s }) }); } object[] myArgs = new object[1] { arrToCopy }; targetProperty.GetSetMethod().Invoke(result, myArgs); } } else { if (smi.ReturnType != typeof(Object)) { object[] myArgs = new object[1] { typeof(MDS_Tools).GetMethod("Copy") .MakeGenericMethod(targetProperty.GetGetMethod().ReturnType) .Invoke(targetProperty, new object[] { smi.Invoke(source, null) }) }; targetProperty.GetSetMethod().Invoke(result, myArgs); } } } } } } return result; } }

Не могу понять принцип единственной обязанности (Single Responsibility Principle)

#ооп #проектирование #solid


В теории все понятно, а на практике постоянно затруднения. Связаны они с тем, что
не понятно в каком масштабе должна рассматриваться эта самая "Единственная обязанность".
Вот нужно мне работать с базой данных. Если я создам класс DataBaseInteracting можно
считать что у него будет одна обязанность? Но ведь тогда он и записывает данные в базу
и читает их оттуда и обновляет. Может лучше создать 3 класса: DataBaseWriter, DataBaseReader
и DataBaseUpdater?
    


Ответы

Ответ 1



Принцип единой обязанности действует практически для любого масштаба: метод, класс, модуль, подсистема и т.д. При выборе обязанности, как и всегда, должна быть некоторая разумность. Более того, от всех принципов иногда можно отступать. Это придет с опытом. В вашем примере я бы сказал, что необходимости в разбиении класса DataBaseInteracting согласно действиям нет. Обязанность "обеспечение хранения данных" достаточно атомарна, на мой взляд, и делить ее на чтение/запись/обновление не нужно. Однако имеет смысл поделить в других плоскостях. Например, если в этом классе есть код построения SQL запросов, то он должен быть вынесен в отдельный класс. Более того, если нужна поддержка нескольких БД, то таких классов должно быть несколько. Т.о. если возникнет потребность какого-то высокоуровневого изменения в "обеспечении хранения данных", вы будете менять класс DataBaseInteracting. Если обнаружится баг с построением неоптимального запроса, вы будете менять класс, который строит запросы и даже не будете трогать DataBaseInteracting. Если вам нужно будет поддержать новую БД, вы просто добавите новый класс. Понимаете? При этом все эти классы должны лежать в проекте DAL. И в этом проекте должно лежать только то, что относится к логике взаимодействия с хранилищем (БД в вашем случае). Так вы поддержите SRP на уровне проекта.

Ответ 2



Так называемый "Принцип единственной ответственности" (SRP) на самом деле не имеет никакого отношения к количеству фич, которые реализует сущность. Принципы SOLID направлены на то, чтобы решать конкретные проблемы, возникающие при работе с кодом, и в случае SRP - это проблема множественных изменений кода при изменении технического задания (ТЗ). Если код, отвечающий за выполнение пункта ТЗ разбросан по многим исходникам, то при изменении этого пункта ТЗ, придется править исходники во многих местах. По этому SRP рекомендует нам собирать весь код, отвечающий за тот или иной пункт ТЗ в одном месте. Чтобы когда ТЗ поменяется, надо было бы править только одно место в коде (один модуль, или один файл, или один класс, или одну функцию, или одну строчку). Из этого следует, что если несколько пунктов ТЗ можно сделать одним куском кода - то это нормально, а вот обратная ситуация - когда на один пункт ТЗ надо много кусков кода - это уже плохо. Ответственность размазывается по исходинкам, SRP не соблюдается, коллеги плачут от коммитов по 40 файлов. По этому если DataBaseInteracting - это один небольшой класс, то с точки зрения SRP - нет никакого смысла разбивать его на DataBaseWriter, DataBaseReader и DataBaseUpdater. Другое дело, что есть другие принципы, например OCP (замена одних кусков кода на другие), или проблема изоляции кусков кода при тестировании.

Ответ 3



Проблема возникает из-за того, что крупные системы состоят из нескольких слоёв, и уровень детализации на каждом слое различается. Поэтому единственную обязанность логично определять для степени детализации характерной для слоя. Поскольку класс DatabaseInteracting кажется мне слишком абстрактным, предложу вместо него рассмотреть известный паттерн Repository (Хранилище). Есть несколько его модификаций, и чтобы не путаться, давайте за основу возьмём модификацию, предложенную Эвансом в книге по DDD. Эванс пишет, что Хранилище обеспечивает долговременное хранение объектов доменной области — это его ответственность. Она реализуется посредством операций чтения, обновления и удаления (сюда же можно присовокупить и создание, но это отличается от канона DDD). Перейдя на уровень ниже (детально рассматривая операции) мы понимаем, что для ускорения работы с базой можно применить модель master-slave, где одна БД считается главной, и ещё несколько — подчинёнными. Подчинённые БД постоянно синхронизируют своё содержание с главной БД, так что на всех серверах одни и те же данные. Запись всегда происходит в главную БД, а читать можно из любой. При большом количестве чтений такая организация приложения даёт существенный прирост в скорости. На этом уровне детализации мы понимаем, что наши подключения к серверу БД будут двух видов: для чтения и для записи-чтения. Соответственно, операция чтения будет создавать подключение первого вида, а операции обновления и удаления — второго. У вас появятся классы ReadOnlyConnection и ReadWriteConnection, но на уровне предметной логики вы будете оперировать только Хранилищем. По своему опыту могу сказать, что причиной неясного кода очень часто является смешение уровней детализации. Здесь должны помочь групповые обсуждения кода или прицельная работа ведущих программистов.

Ответ 4



Во-первых, этот принцип очень спорный и потому почти не применим на практике. Почти никогда нет ТЗ, по которому пишется программный продукт. А если подробное ТЗ есть, то оно уже не меняется. Кроме того, совершенно очевидно, что для любого ТЗ можно легко придумать такую правку, из-за которой придется радикально переписывать программу. Ведь разные части программы опираются на одни и те же идеи из ТЗ, которые могут измениться. Во-вторых этот принцип противоречит принципу KISS (keep it simple stupid / чем проще, тем лучше), одному из немногих, который действительно работает при дизайне системм. Если вы разбиваете объект на части, то усложняете программу, вместо одного класса у вас получается 2, 3, 4 и больше. В результате, зачастую, если исходную программу можно было легко понять, то "улучшенную" уже сложно, т.к. в ней много объектов и они все не помещаются в сознание. тут подробнее

Развивается ли СУБД Access? [закрыт]

#sql #access #office


        
             
                
                    
                        
                            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 3 года назад.
                                                                                
           
                
        
Например, Microsoft при новых версиях MS SQL Server говорит, что стоимость запросов
уменьшается, производительность повышается и все такое(т.е все круто), а про новые
Access ничего подобного не встречал.

Собственно вопрос, а идет ли какое-либо развитие в плане производительности в СУБД
Access или нет?

Мне довелось использовать  2007,2013,2016 и как стопорились они на запросах, которые
проглатывает на ура MS SQL так и стопорятся.

Мне кажется, что в Access до сих пор не задействует потенциал многоядерных процессоров.

Даже допустимый размер БД с 2гб не повышают.
    


Ответы

Ответ 1



Access - это SOHO - решение - для дома и МАЛОГО офиса, оно не предназначено для поддержки огромных баз. А раз так, то и вкладывать в него усилия R&D нет смысла.

Ответ 2



Думаю что вы правы и как СУБД MS Access не развивается уже лет 10. Но и собственно зачем его развивать? Движение идёт в сторону мобильных, где в качестве БД есть MS SQL Compact. Другое направление развития -- это веб-приложения, но там по части БД довольно широкий выбор. Вот документ, в котором Jet 4.0 объявляется устаревшим: https://msdn.microsoft.com/en-us/library/ms810810.aspx

Регулярное выражение для получения id пользователя

#javascript #регулярные_выражения


В общем, нужно вывести из строки id пользователя до запятой. В данном коде выводит
"id50,", надо только "50". Как?)

   text = 'id50, 4124fdgfgdfg';
      if(text.match('id[0-9].*,')){
        komy = text.match('id[0-9].*,');
        alert(komy);
      }

    


Ответы

Ответ 1



С помощью регулярного выражения ^id(\d+),.*$ (захватывается число в скобках после id, и до запятой). Можно сразу захватить и вторую часть (4124fdgfgdfg), таким выражением: /^id(\d+), (.*)$/. Рабочий пример: str = 'id42, 4124fdgfgdfg'; if (m = str.match(/^id(\d+), (.*)$/)) { console.log(m[1], m[2]) } Дает в консоль (можете нажать кнопку "Выполнить код" для проверки): 42 4124fdgfgdfg Здесь хорошее описание match на русском: https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/String/match Здесь https://regex101.com/ вы можете онлайн поиграть с регулярными выражениями и сразу видеть результат. Вот ваш пример с тестами и комментариями: https://regex101.com/r/nX1rF5/2

Ответ 2



Вариантов куча: Можно поправить само выражение и будет работать: // (?<=id) - смотрит позитивно назад, но не берёт в результат // (?=,) - смотрит позитивно вперёд, но не берёт в результат // + перед выражением пытается привести результат к Number // // Вернётся либо ["50"], либо null; // массив с одним элементом попытается привести первый элемент // null станет 0 // Используйте эти знания на благо Вашей проверки :) console.info(+/(?<=id)\d*(?=,)/.exec('id50, 4124fdgfgdfg')); // 50 Можно, конечно, использовать старые, добрые группы (можно даже именованные сделать): // С помощью тернарного оператора проверяем на null // Если null - вернём 0 // Если есть результат - приводим к Number 1 элемент (в 0 - всё совпадение, т. е. id50,) console.info((r = /id(\d*),/.exec('id50, 4124fdgfgdfg')) ? +r[1] : 0); // 50 Можно извращаться типа String.prototype.split заюзать, где с помощью тех же групп сохраняется номер, но зачем использовать ножовку для забивки гвоздей?

Ответ 3



При match или exec придётся использовать дополнительные проверки, иначе возможна ошибка Cannot read property '1' split либо найдёт, либо нет (undefined) text = 'id50, 4124fdgfgdfg'; t = text.split(/id(\d+), (.*)/); console.log(t[1], t[2]);

Ответ 4



text = ' id50, 4124fdgfgdfg'; console.log(text.replace(/id(\d+)\s*,.*|./gi, '$1')) text = ' id50, 4124fdgfgdfg id100,'; console.log(text.replace(/id(\d+)\s*,.*|./gi, '$1')) text = ' id, 4124fdgfgdfg'; console.log(text.replace(/id(\d+)\s*,.*|./gi, '$1'))

Ответ 5



Никак, но можно так (вместе с id): /id\d[^,]*/

Как передать шаблон функции в другую функцию?

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


Как правильно написать функцию test, чтобы ей в качестве аргумента (либо шаблонного
параметра - не важно) можно было передать любую из функций f и g, с возможностью их
вызова с разным типом аргумента (в примере int, char и long).

http://ideone.com/1aZ8Zu

#include 

using namespace std;

template  auto f(T x) -> decltype(x*x)
{
  return x * x;
}

template  T g(T x)
{
  return x * x;
}

template