Страницы

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

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

Несколько EditText с одинаковым ID

#java #android


В LinearLayout циклом добавляется фрагмент, укомплектованный в другом .xml файле.
Фрагмент содержит три EditText. 

Задача: достать текст из каждого первого/второго/третьего EditText во всех фрагментах.

Помогите, пожалуйста.
    


Ответы

Ответ 1



В цикле бежите по View которые внутри LinearLayout, достаёте фрагмент, а у него обращаетесь к editText LinearLayout linearLayout = initLayout(); int count = linearLayout.getChildCount(); Fragment f = null; String reduce = ""; for(int i=0; i

Ответ 2



((EditText)myFragment.getView()).findViewById(R.id.edt).getText().toString(); чтобы на getView() не вылетал NullPointerExeption, при вызове этого метода фрагмент точно должен быть добавлен. При получении значений из edt, по идее, он уже должен отображаться, просто будьте внимательны.

Регулярное выражение для поиска непоследовательных дубликатов слов

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


([[a-zа-я|А-Я]+)([[:space:]]+)\1


Данное регулярное выражение позволяет найти в тексте дубликаты слов, которые следует
друг за другом. Например:
"Что мне мне делать".
Но каким должно быть регулярное выражение, если я хочу найти непоследовательно повторяющиеся
слова?
    


Ответы

Ответ 1



Можно воспользоваться следующим выражением: SELECT * FROM regexTest WHERE REGEXP_LIKE( test, '([^_a-zA-Z0-9а-яА-ЯёЁ]|^)([a-zA-Zа-яА-ЯёЁ]+)[^_a-zA-Z0-9а-яА-ЯёЁ].*\2', 'i') См. демо регулярного выражения. Подробности ([^_a-zA-Z0-9а-яА-ЯёЁ]|^) - Захватываемая подмаска №1 (в регулярках Oracle нет поддержки незахватываемых групп): любой 1 символ, отличный от английских и русских букв, цифр и знака подчёркивания ([^_a-zA-Z0-9а-яА-ЯёЁ]) или (|) начало строки (^) ([a-zA-Zа-яА-ЯёЁ]+) - Захватываемая подмаска №2: 1 и более английских или русских букв [^_a-zA-Z0-9а-яА-ЯёЁ] - любой 1 символ, отличный от английских и русских букв, цифр и знака подчёркования .* - 0 и более любых символов, отличных от знака перевода на новую строку (если использовать модификатор n (т.е. третий аргумент должен быть 'in'), можно найти повторяющиеся слова на разных строчках строки) \2 - обратная ссылка на значение захватываемой подмаски №2. См. SQL-демо: CREATE TABLE regexTest( test varchar2(50)); INSERT INTO regexTest VALUES ('Что мне тут мне делать'); INSERT INTO regexTest VALUES ('Что мне мне делать'); INSERT INTO regexTest VALUES ('Что тут мне делать'); INSERT INTO regexTest VALUES ('Что делать? Дела?'); INSERT INTO regexTest VALUES ('Дела,дела...'); INSERT INTO regexTest VALUES ('Ничего-ничего, так себе...'); COMMIT; SELECT * FROM regexTest WHERE REGEXP_LIKE(test, '([^_a-zA-Z0-9а-яА-ЯёЁ]|^)([a-zA-Zа-яА-ЯёЁ]+)[^_a-zA-Z0-9а-яА-ЯёЁ].*\2') Результат: TEST Что мне тут мне делать Что мне мне делать Дела,дела... Ничего-ничего, так себе... Флаг 'i' позволяет находить повторяющиеся слова в разных регистрах. Если его убрать, будут найдены только 2 результата: Что мне тут мне делать Что мне мне делать

Ответ 2



Так найти только первое совпадение (см. демо регулярного выражения): select regexp_substr (str, pattern) match from ( select 'не как то что мне не мне что' str, '(^|\s)(\w+)\s.*\S+.*\s\2(\s|$)' pattern from dual ); match --------------------- не как то что мне не Если нужны все дубликаты, то самое простое, двигаться вперёд по словам (граница первого слова будет всегда начало строки - ^: select regexp_substr (substr(str, nextWordPos), pattern) match from ( select str, pattern, regexp_instr (str, '\w+', 1, level) nextWordPos from ( select 'не как то что мне не мне что' str, '^(\w+)\s.*\S+.*\s\1(\s|$)' pattern from dual ) connect by level < regexp_count (str, '\w+') -1 ) where regexp_substr (substr(str, nextWordPos), pattern) is not null ; match ------------------------------------------------- не как то что мне не что мне не мне что мне не мне Движок регулярных выражений Oracle имеет целый ряд ограничений, например, отсутствие границ слова (\b), нет поддержки незахватываемых групп, поиска вокруг и т.д. Если всё же надо обойти эти ограничения, то можно реализовать свою функцию, например, на Java. Пример (демо регулярного выражения): select column_value match from table (getMatches ( 'не как то что мне не мне что', '\b([\p{L}\p{N}_]+)\b(?=.*(\b\1\b))' )); Вывод: match ----------------------------------------- не at 0/2 has duplicate at 18/20 что at 10/13 has duplicate at 25/28 мне at 14/17 has duplicate at 21/24 Сама функция: create or replace type matchesType is table of varchar2(256); / create or replace and compile java source named "Utils" as import java.lang.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.List; import java.util.ArrayList; public class Match { public static java.sql.Array getMatches (String input, String pattern) throws java.sql.SQLException { return OraUtils.toSqlArray ("matchesType", getMatchesArray (input, pattern)); } private static String[] getMatchesArray (String input, String pattern) { List matches = new ArrayList(); Matcher m = Pattern.compile (pattern).matcher (input); while (m.find()) { matches.add (m.group()+" at "+m.start()+"/"+m.end ()+" has duplicate at "+m.start(2)+"/"+m.end(2)); } return matches.toArray (new String[0]); } } public class OraUtils { static java.sql.Array toSqlArray (String typeName, Object elements) throws java.sql.SQLException { oracle.jdbc.OracleDriver ora = new oracle.jdbc.OracleDriver(); oracle.jdbc.OracleConnection oraConn = (oracle.jdbc.OracleConnection) ora.defaultConnection(); java.sql.Array arr = oraConn.createARRAY(typeName.toUpperCase(), elements); return arr; } }; / create or replace function getMatches (s varchar2, p varchar2) return matchesType deterministic as language java name 'Match.getMatches (java.lang.String, java.lang.String) return java.sql.Array'; / Начиная с версии Java 7 (БД 12.1, 12.2) можно пользоваться \w+ для юникодов с флагом Pattern.UNICODE_CHARACTER_CLASS. Ожидать той же производительности, как и у функций внутреннего движка, не следует.

Android, как сохранять данные без базы данных?

#java #android


Только начала учить Android, пишу в Android Studio. Есть на уме идея для одной программы,
но для этого мне надо научиться сохранять данные. Слышала, что использовать SqlLite
нужно только при больших объемах памяти. Мне же, грубо говоря, нужно сохранять только
имя пользователя и ещё какую-то общую информацию и выводить это в List. Как мне это
сделать? Как правильно сохранять эти данные? В какой-то массив или отдельный файл?
    


Ответы

Ответ 1



Для сохранения данных вы можете использовать SharedPreferences SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(MainActivity.this); Чтобы начать запись в файл настроек, вы должны вызвать метод edit() объекта SharedPreferences, который возвращает объект SharedPreferences.Editor. SharedPreferences.Editor editor = sharedPreferences.edit(); Объект SharedPreferences.Editor имеет несколько интуитивных методов, которые можно использовать для хранения новых пар ключ-значение в файле настроек. Например, вы можете использовать метод putString(), чтобы поместить пару ключ-значение со значением типа String editor.putString("name", "Danil"); editor.putInt("age", 20); Чтобы сохранить записи вы должны вызвать метод commit(). editor.commit(); Чтение из объекта SharedPreferences гораздо проще. Всё, что вам нужно сделать, так это вызвать соответствующий метод get*() String name = sharedPreferences.getString("name", "unknown"); int age = sharedPreferences.getInt("age", 0);

Ответ 2



Основными вариантами хранения данных в Android, являются: сохранение пар "ключ-значение" для простых типов данных в общем файле настроек (SharedPreferences); использование баз данных под управлением SQLite; сохранение произвольных файлов в файловой системе Android. Так как мы выяснили, что в вашем случае SharedPreferences вам не подходят, а базой данных вы по каким-то причинам не хотите воспользоваться, то рассмотрим вариант сохранение произвольных файлов в файловой системе Android. Для этого стоит воспользоваться объектом File который подходит для чтения или записи больших объемов данных в порядке от начала к концу без пропусков. Для того чтобы воспользоваться данным способом первоначально следует определиться где вы будете сохранять свой файл, во внутренней или внешней памяти. Свойства внутренней памяти: всегда доступно. сохраненные здесь файлы по умолчанию доступны только вашему приложению. при удалении пользователем вашего приложения система Android удаляет из внутренней памяти все файлы этого приложения. Свойства внешней памяти: доступно не всегда, потому что пользователь может в любое время подключать и отключать такие хранилища. такие хранилища доступны для чтения везде, поэтому вы не контролируете чтение сохраненных в них данных. при удалении пользователем вашего приложения система Android удаляет из внешних хранилищ файлы этого приложения, только если они сохраняются в директории с использованием getExternalFilesDir(). Рассмотрим вариант сохранения файла во внутренней памяти. При сохранении файла во внутреннюю память вы можете получить соответствующую директорию в виде File, вызвав один из двух методов: getFilesDir() - возвращает File, соответствующий внутренней директории приложения. getCacheDir() - возвращает File, соответствующий внутренней директории файлов временной кэш-памяти приложения. Для создания файла в одной из этих директорий можно использовать конструктор File(), который передает элемент File, предоставляемый одним из вышеприведенных методов, с помощью которого указывается директория во внутренней памяти. Например: File file = new File(context.getFilesDir(), filename); Кроме того, можно вызвать метод openFileOutput() для получения объекта FileOutputStream , производящего запись в файл во внутренней памяти. Вот пример записи текста в файл: String filename = "myfile"; String string = "Hello world!"; FileOutputStream outputStream; try { outputStream = openFileOutput(filename, Context.MODE_PRIVATE); outputStream.write(string.getBytes()); outputStream.close(); } catch (Exception e) { e.printStackTrace(); }

Почему в примере из книги true

#cpp


const char* p = "Heraclitus" 
const char* q = "Heraclitus" 
void g ()
{
    if(p==q) cout<<"one! \n"; //результат зависит от конкретной реализации
}


Б. Страуструп

Суть в том что адреса разные, а пишут вот что:


  Обратите внимание на то, что для указателей операция == сравнивает
  адреса (значения указателей), а не адресуемые ими величины.


Если сравниваются адреса, то как может быть true, если при компиляции явно разные адреса?
    


Ответы

Ответ 1



Компилятору разрешается (но не требуется) в качестве оптимизации хранить одинаковые строковые литералы* в одном и том же месте. Если компилятор это делает, то адреса будут одинаковые. Если не делает - разные. *Литерал - безымянная константа в исходном коде. x, 'y', 123, "hello" - все это литералы. "hello" - строковый литерал.

Ответ 2



У вас в коде нет адресов, а только указатели. Значение равенства будет true, т к оба указателя указывают на одно и то же место.

Как правильно в модели базы данных связывать (хранить) данные о наблюдений за птицами?

#sql #база_данных #модель_данных


Делаю базу данных наблюдений за птицами. Выделил отдельные "справочники", возникла
проблема теперь с объединением этих данных. Т.е. нужна таблица, которая бы хранила
результат наблюдений:

Примеры данных наблюдений:


10.10.18 Андрей наблюдает среднюю стаю
11.10.18 Дмитрий наблюдает большую стаю, в стае имеются вороны, сороки
12.10.18 Дмитрий наблюдает среднюю стаю и большую стаю
12.10.18 Антон наблюдает ворон, аистов.


Выделил таблицы:


Виды птиц
Размер стаи
Тип объекта (Стая/Птица)
Источник наблюдений


Нужна таблица, в которой фиксировалась бы данные наблюдений. 


Не могу сообразить, как это сделать. Как будто я что-то упустил.
Не могу понять, как сделать так, чтобы можно было фиксировать:


размер стаи
размер стаи + виды птиц в стае
так и отдельно виды птиц



Подскажите пожалуйста.

    


Ответы

Ответ 1



Вам нужно завести еще одну таблицу Факты, которая связана с таблицей наблюдений как 1 ко многим: В этом случае каждая запись в таблице факты с идентификатором конкретного наблюдения будет означать что там увидели еще Если в таблице Факты будут 4 записи с одинаковым идентификатором наблюдения со ссылками на размер стаи, на вид птицы вороны, аисты и сороки. Тогда это будет трактоваться так: 11.10.18 Дмитрий наблюдает большую стаю, в стае имеются вороны, аисты и сороки

Ответ 2



Вам нужно создать таблицу "Объект наблюдения" в которой создать поля для храниеия ID стаи, ID птицы, размер стаи, тип объекта (стая или птица). Потом ID этой таблицы вписавать в "Данные наблюдений".

Ответ 3



Мне кажется, наблюдения лучше сделать немного более детальными. Одна запись наблюдения - один вид. Также добавить поля "количество", "пол" и "возраст". Возраст точно определить нельзя, но птенцы всегда отличаются от родителей, а иногда и взрослые птицы долго не меняют подростковую окраску. Например, бакланы и лебеди в возрасте около года примерно отличаются по окраске от взрослых, но не отличаются по размеру. Значения там будут примерно такие: птенец подросток взрослая особь В базах наблюдений, с которыми я имел дело, обычно какое-то такое поле есть. Если точное количество неизвестно, можно добавить справочное поле "размер стаи" с вариантами, например, 1 - 10, 10 - 50, 50 - 100, больше 100. И заполнять либо точное количество, либо приблизительное. Но обычно с подсчетом проблем не возникает: на практике большинство наблюдателей просто делает фото, а дома, в спокойной обстановке, вооружившись фотошопом, пересчитывает. Ну и дополнительные поля типа даты, времени, координат и т. п. Это будет сущность "наблюдение птицы" (или факт, как Barmaley предложил), а несколько таких наблюдений, сделанных за один выезд "в поле", объединять в сущность "наблюдение". UPD. Добавлю схему: И немного пояснений. "Сессия наблюдений" (observation_session) - это один "заход". Например, наблюдатель Маша Иванова 01.01.2018 выехала в поле и два часа шла из пункта А в пункт Б, делая наблюдения. Этому событию соответствует одна запись в этой таблице. Далее каждая встреченная во время этой сессии наблюдений птица заносится отдельной строкой в таблицу observation. Из справочников подтягиваются пояснения - какой вид, сколько птиц, и так далее. Если точное количество установить не удается, можно записывать приблизительное из справочника bird_group, но я честно говоря не представляю, что вы с ним потом будете делать. Потому что по факту это количество, но работать с полем как с числом вы не сможете, только делать оценки уровня "плюс-минус километр". P. S. Бердвотчер-любитель со стажем, если что ;)

Одновременное обновление родительской и дочерней таблицы по ключу

#sql #oracle


Есть table1 c tab1_id primary key  и table2 c tab1_id foreign key. 
Нужно изменить table1.tab1_id.
При попытке изменить tab1_id в любой из таблиц ругается на нарушение целостности:

Update table1 set tab1_id = 22 where tab1_id = 11



  ORA-02292: "обнаружена порожденная запись"


Update table2 set tab1_id = 22 where tab1_id = 11



  ORA-02292: "Исходный ключ не найден".


Можно ли сделать апдейт сразу в 2 таблицы? Или как обойти это ограничение не внося
ограничение в структуру таблицы (без alter table)?
    


Ответы

Ответ 1



Вариант 1: шаг 1. выключаем внешние ключи(alter table disable constraint) шаг 2. обновляем данные для обоих таблиц(update table1 set tab1_id = .., update table2) шаг 3. включаем обратно внешние ключи(alter table enable constraint) Вариант 2: Объявляем наш constraint как defferable. alter table table2 add constraint constraint_name foreign key (tab1_id) references table1(tab1_id) deferrable; Обновление таблицы выполняем в PL\SQL блоке: begin execute immediate 'set constraint constraint_name deferred'; update table1 ..; update table2 ..; commit; end; PS: У вас что-то странное с архитектурой БД. При правильной архитектуре не должно возникать ситуации, когда необходимо править ID.

Ответ 2



Если возник такой вопрос, значит скорее всего вследствии ошибки "поломан" не один единственный ключ. В этом случае, надо: ограничить доступ к БД переведя её в restricted session mode отключить внешние ключи с alter table t2 modify constraint t2_fk1 disable; изменить ключи снова включить ключи и перевести БД в нормальный режим. Если это всё-таки единичный случай, можно сделать move (скопировать-удалить в одной транзакции), например: create table t1 (id number primary key); create table t2 ( id number, memo varchar2 (32), constraint t2_fk1 foreign key (id) references t1(id) ); insert into t1 values (11); insert into t2 select 11, 'memo'||rownum from xmlTable ('1 to 2'); create or replace procedure moveKeys (oldId number, newId number) is newRow t1%rowtype; begin select * into newrow from t1 where id = oldId; newRow.id := newId; insert into t1 values newRow; update t2 set id = newId where id = oldId; delete t1 where id = oldId; end; / exec moveKeys (11, 22); commit; select * from t1 join t2 on t2.id = t1.id; ID ID MEMO ---------- ---------- -------------------------------- 22 22 memo1 22 22 memo2

Как такое реализовать на canvase?

#javascript #html #canvas


Нужно чтобы карта была в целом 1000на1000, но ВИДНАЯ часть лишь 100на100, как это
сделать? Можно ли как-то указать координаты начала ВИДИМОГО экрана и его конец.
    


Ответы

Ответ 1



let cameraWidth = 100; let cameraHeight = 100; let camera = document.getElementById("camera"); let canvas = document.getElementById("canvas"); document.addEventListener("mousemove", function(e) { // Motion camera.style.left = e.clientX - cameraWidth / 2 + "px"; camera.style.top = e.clientY - cameraHeight / 2 + "px"; canvas.style.left = -e.clientX + "px"; canvas.style.top = -e.clientY + "px"; }); #camera { position: absolute; width: 100px; height: 100px; border: 2px solid #ccc; overflow: hidden; } #canvas { position: absolute; width: 500px; height: 300px; background: url(http://www.tedgoas.com/content/blog/22-stack-overflow-design/-stack-overflow-cover.jpg) no-repeat; }


Ответ 2



Набросал на коленке решение. Создаю огромную карту тайлов 200 на 200. Генерю в каждый тайл случайный цвет, но с градиентом на всю карту, чтоб было заметно как окно движется над картой. Затем запускаю над картой окно по кругу против часовой стрелки начиная с правого края карты. Рендерятся только видимые тайлы. Может где ошибся и есть погрешности округления, но думаю можно меня простить :) Главное, что суть понятна. Math.rad = function(deg) { return deg * Math.PI / 180; }; let tilesTotalX = 200, tilesTotalY = 200, tilesVisibleX = 10, tilesVisibleY = 7, tileWidth = 20, tileHeight = 20; let worldSize = { w: tilesTotalX * tileWidth, h: tilesTotalY * tileHeight }; let windowSize = { w: tilesVisibleX * tileWidth, h: tilesVisibleY * tileHeight }; let tiles = []; for (let row = 0; row < tilesTotalY; row++) { tiles.push([]); for (let col = 0; col < tilesTotalX; col++) { let r = (Math.floor(0xFF * (row / tilesTotalY))).toString(16), g = (Math.floor(0xFF * (col / tilesTotalX))).toString(16), b = (Math.floor(0xFF * Math.random())).toString(16); tiles[row].push(`#${r}${g}${b}`); } } let angle = 0, step = .3; let circle = { x: Math.round((worldSize.w - windowSize.w) / 2), y: Math.round((worldSize.h - windowSize.h) / 2), r: Math.round(((worldSize.h - windowSize.h) / 2) * .8), }; let ctx = c.getContext("2d"); ctx.fillStyle = "#f0f0f0"; ctx.fillRect(0, 0, windowSize.w, windowSize.h); let fps = 16, fpsInterval = 1000 / fps, then = Date.now(); (function animate(){ requestAnimationFrame(animate); let now = Date.now(), elapsed = now - then; if (elapsed > fpsInterval) { then = now - (elapsed % fpsInterval); angle += step; angle %= 360; //console.log(angle); let windowPosition = { x: Math.round(circle.x + Math.cos(Math.rad(angle)) * circle.r), y: Math.round(circle.y - Math.sin(Math.rad(angle)) * circle.r) }; let firstVisibleRowIndex = Math.floor(windowPosition.y / tileHeight), firstVisibleColIndex = Math.floor(windowPosition.x / tileWidth), lastVisibleRowIndex = Math.floor((windowPosition.y + windowSize.h) / tileHeight), lastVisibleColIndex = Math.floor((windowPosition.x + windowSize.w) / tileWidth); let offset = { x: windowPosition.x - tileWidth * Math.floor(windowPosition.x / tileWidth), y: windowPosition.y - tileHeight * Math.floor(windowPosition.y / tileHeight) }; ctx.save(); ctx.translate(-offset.x, -offset.y); for (let row = firstVisibleRowIndex; row <= lastVisibleRowIndex; row++) { for (let col = firstVisibleColIndex; col <= lastVisibleColIndex; col++) { ctx.fillStyle = tiles[row][col]; ctx.fillRect( tileWidth * (col - firstVisibleColIndex), tileHeight * (row - firstVisibleRowIndex), tileWidth, tileHeight ); } } ctx.restore(); } })();