11 заметок с тегом

программирование

Сделай сам

Повторное использование чужих приемов — это нормально

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

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

Я не люблю ковыряться в чужом коде или разбираться в документации чьей-то библиотеки, так как при этом ничего не получаю взамен, кроме усталости и отупения.

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

 Нет комментариев    36   2022   Гоген   картина   Пикасо   прием   программирование

Ассоциативный массив в старых версиях Дельфи

В Королевстве Дельфи много лет назад Дмитрий Рябов предложил реализацию ассоциативных массивов.

«На практике часто возникает потребность сохранять и обрабатывать данные в массивах, осуществляя доступ к элементам не по индексу, а по ключу. Для этого используются ассоциативные массивы, которые есть, например, во многих скриптовых языках. В Delphi на уровне языка такая структура отсутствует. В качестве замены часто используются контейнерные классы TStringList, TParams и т. п., но они весьма неудобны в использовании и недостаточно функциональны. К тому же появляется необходимость заботиться об уничтожении экземпляра класса, что зачастую порождает лишние try..finally..end

В чем фишка реализации.

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

Я иногда ее использую в своих проектах и всегда опасаюсь, что текст с примерами будет окончательно потерян. Потому решил воспроизвести его здесь.


program Example;
{$APPTYPE CONSOLE}
uses
  Arrays;

procedure Main;
var
  I: IIntArray;
  S: IStrArray;
  V: IVarArray;
  M: IMltArray;

begin
  // создаём массив и получаем представление в целых числах
  I := CreateArray;

  // заполняем
  I['a'] := 5;
  I['b'] := 1;
  I['c'] := 4;
  I['d'] := 2;
  I['e'] := 3;

  // выводим
  WriteLn('Original array');
  I.First;
  while not I.Eof do
  begin
    WriteLn('[', I.CurrentKey, '] = ', I.CurrentValue);
    I.Next;
  end;

  // сортируем
  I.Sort;

  // наблюдаем результат
  WriteLn('Sorted array');
  I.First;
  while not I.Eof do
  begin
    WriteLn('[', I.CurrentKey, '] = ', I.CurrentValue);
    I.Next;
  end;

  // создаём строковое представление
  S := I.Instance;

  // наблюдаем результат
  WriteLn('Two views of one array');
  S.First;
  while not S.Eof do
  begin
    WriteLn('[', S.CurrentKey, '] + ''10'' = ', S.CurrentValue + '10');
    WriteLn('[', I.CurrentKey, '] + 10 = ', I.CurrentValue + 10);
    S.Next;
  end;

  // создаём вариантное представление
  V := S.Instance;
  V.Clear;
  V['integer'] := 10;
  V['string'] := '10';

  // наблюдаем результат
  WriteLn('Variant type conversion');
  V.First;
  while not V.Eof do
  begin
    WriteLn('[', V.CurrentKey, '] + 10 = ', V.CurrentValue + 10);
    WriteLn('[', V.CurrentKey, '] + ''10'' = ', V.CurrentValue + '10');
    V.Next;
  end;

  // используем ключи разных типов, но одного значения
  S.Clear;
  S[False] := 'boolean';
  S[0] := 'integer';
  S[0.0] := 'float';
  S['0'] := 'string';

  // наблюдаем результат
  WriteLn('Variant type keys ;)');
  S.First;
  while not S.Eof do
  begin
    WriteLn('[', S.CurrentKey, '] = ', S.CurrentValue);
    S.Next;
  end;

  // создаём ещё одно представление, на этот раз - многомерное
  M := V.Instance;
  M.Clear;

  // заполняем матрицу
  M['A']['a'].AsInteger := 1;
  M['A']['b'].AsInteger := 2;
  M['A']['c'].AsInteger := 3;
  M['B']['a'].AsInteger := 4;
  M['B']['b'].AsInteger := 5;
  M['B']['c'].AsInteger := 6;
  M['C']['a'].AsInteger := 7;
  M['C']['b'].AsInteger := 8;
  M['C']['c'].AsInteger := 9;

  // выводим матрицу
  WriteLn('Multidimensional array');
  M.First;
  while not M.Eof do
  begin
    M.CurrentValue.First;
    while not M.CurrentValue.Eof do
    begin
      WriteLn('[', M.CurrentKey, ',', M.CurrentValue.CurrentKey, '] = ',
        M.CurrentValue.CurrentValue.AsInteger);
      M.CurrentValue.Next;
    end;
    M.Next;
  end;

  // перед возвратом все созданные массивы автоматически удаляются
  WriteLn('Arrays is free');
end;

var
  L: Integer;
begin
  L := AllocMemSize;
  Main;
  // проверка утечки памяти
  WriteLn('Memory leak: ', AllocMemSize - L, ' bytes');
  ReadLn;
end.

Скачать исходники из Королевства

Посмотреть рекомендацию оссоциативного массива на Стакэксчендже .

 Нет комментариев    109   2022   ассоциативный массив   дельфи   программирование

Прием программирования: Вовремя остановиться

Иногда я пишу одноразовый код, который, например, что-то переносит из файла в базу данных. Этот код мне понадобиться один раз, но удалять его после использования жалко.

Для того, чтобы код нельзя было больше выполнить, я внедряю в него оператор die().

Главное — вовремя остановиться.

 Нет комментариев    114   2021   прием   программирование   ПХП

Приемы программирования. Вернуть вектор

Иногда функция должна вернуть не одно, а несколько значений. Например флаг успеха или неудачи, несколько найденных параметров и массив. Фактически она возвращает векторный результат.

Раньше для получения векторного результата я передавал несколько переменных по ссылке и ждал булево значение функции.

// Здесь ожидаю два параметра и двумерный массив, а функция возвращает флаг успеха-неудачи.
function navalniy( 
    source_data : TVector; var temperature : real; var blood_pressure : real; var spy_data : TVector
) : boolean;

Теперь я просто получаю один векторный результат.

function navalniy( source_data : TVector ) : TVector;

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


spy_data = navalniy( source_data );
if (spy_data[0][0] == 0) {
  alert(‘Явка провалена. Немедленно уходить!’);
  exit();
} else {
  temperature = spy_data[0][1];
  blood_pressure = spy_data[0][2];
  list_of_comrades = (spy_data[1], …, spy_data[M]);
  // Все в порядке, продолжаем готовить революцию
  // …
}

Единственное, при таком подходе нужно следить, чтобы размерность второй координаты массива (resulted_array[•][×]) была не меньше размерности ожидаемых дополнительных параметров (param{i}). В противном случае параметры следует вернуть в нескольких начальных компонентах ветора-результата.


spy_data = navalniy( source_data );
if (spy_dat[0][0] > 0) {
  temperature =spy_dat[0][1];
  blood_pressure = spy_dat[0][2];
  leukocytes = spy_datt[1][0];
  hemoglobin = spy_dat[1][1];
  erythrocytes = spy_dat[1][2];
  // Возвращенный массив начинается с N-ой компоненты вектора-результата
  list_of_comrades = (spy_dat[N], …, spy_dat[M]);
  // …
}

Векторы — это сила.

 Нет комментариев    83   2020   вектор   прием   программирование

Приемы веб-программирования. Разрешить Апачу сначала искать файлы в текущем каталоге

Памятка тем, кто (до сих пор) руками пишет веб-движки на ПХП.

У вас есть два файла с одинаковым названием ’konstituciya.php’ в текущем и каком-то системном каталоге. Файл в системном каталоге делает основную работу, например, выводит перечень статей конституции. Файл в текущем каталоге устанавливает локальные настройки, например, вносит в конституцию поправки, а потом вызывает файл из системного каталога. Чтобы поправки вступили в силу, необходимо, чтобы первым был вызван файл из текущего каталога. Вот так:

konstituciya.php → ./system/konstituciya.php

Чтобы установить такую последовательность вызовов, в .htaccess в списке путей первой поставьте точку, а потом перечислите прочие каталоги:

php_value include_path ".:/home/system"

Тогда код выполнится правильно:

// Сначала вызовет файл из текущего каталога с поправками, а потом системный файл с основными законами
   include_once "konstituciya.php";

Удачи.

 Нет комментариев    166   2020   конституция   поправки   прием   программирование   ПХП

Приемы программирования. Залить файлы на сервер

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

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

Именно так я тестирую «Фотосистематизатор».

Фотосистематизатор берет фотографии прямо из каталога, а пользователь закачивает их туда напрямую, без интерфейсных наворотов
 Нет комментариев    462   2020   прием   программирование   фотосистематизатор

Приемы программирования. Ненужный файл с кодом не удаляю, а переименовываю

Бывает, что файл с фрагментом кода уже не нужен. Например потому, что код из него переписан, усовершенствован и перенесен в другой файл. Тогда такой файл я сразу не удаляю, а приписываю к нему приставку ’del-’.

После тестирую, нет ли ошибок и все ли работает правильно. Потом жду несколько дней и только после этого бесповоротно удаляю файл.

 Нет комментариев    330   2020   прием   программирование

Ошибки программирования. Забыл про юникод

В коде повторяю одни и те же ошибки. Из-за них ничего не работает. Вот одна.

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

if (strtolower($input_name) == $name) { ... }

В результате функция strtolower вместо строчных русских букв выдала мусор. Сравнение не сработало. Процесс пошел по другой ветке. Пользователь в панике.

А правильно использовать mb_strtolower.

if (mb_strtolower($input_name) == $name) { ... }

То же самое относиться и к другим функциям работы со строками. При юникоде и других кодировках использовать функции с префиксом mb_.

Успехов.

 Нет комментариев    41   2020   ошибки   программирование   ПХП

Как быстро закомментировать блоки кода

Блок — это фрагмент кода заключенный в условный оператор или цикл.

if (push_index > 0 ) {
  // Блок кода
}

for (i=0; i < row_of_areolae.length-1; i++) {
  // Блок кода
}

while (level < maximal_level) {
  // Блок кода
}

Чтобы быстро исключить блок кода из потока программы, достаточно к условию дописать выражение «Ложь и».

if (false && push_index > 0 ) {
  // Блок кода
}

for (i=0; false && i < row_of_areolae.length-1; i++) {
  // Блок кода
}

while (false && level < maximal_level) {
  // Блок кода
}

Когда фрагмент кода не содержится в цикле или условном операторе, но его нужно то закомментировать, то оставить — принудительно заключаем его в блок. Потом меняем условие блока на «Истину» или «Ложь».

// Фрагмент выполняется
if (true) {
	angle = g_sectors[i].fi[1] - ksi;
	k = new_areolae.length-2;
	while ((k>push_index) && (angle>=g_sectors[i].fi[0])) {
		new_areolae[k][3] = angle;
		new_areolae[k][0] = Math.cos(angle)*level_po;
		new_areolae[k][1] = Math.sin(angle)*level_po;
		//pivot_areola = new_areolae[k];
		angle -= ksi;
		k--;					
	}
}

// Фрагмент не выполняется
if (false) {
	angle = g_sectors[i].fi[1] - ksi;
	k = new_areolae.length-2;
	while ((k>push_index) && (angle>=g_sectors[i].fi[0])) {
		new_areolae[k][3] = angle;
		new_areolae[k][0] = Math.cos(angle)*level_po;
		new_areolae[k][1] = Math.sin(angle)*level_po;
		//pivot_areola = new_areolae[k];
		angle -= ksi;
		k--;					
	}
}

Чтобы закомментировать тот же фрагмент кода, надо поставить символы комментария в его начале и конце.

/*
	angle = g_sectors[i].fi[1] - ksi;
	k = new_areolae.length-2;
	while ((k>push_index) && (angle>=g_sectors[i].fi[0])) {
		new_areolae[k][3] = angle;
		new_areolae[k][0] = Math.cos(angle)*level_po;
		new_areolae[k][1] = Math.sin(angle)*level_po;
		//pivot_areola = new_areolae[k];
		angle -= ksi;
		k--;					
	}
*/

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

 1 комментарий    46   2019   прием   программирование

Директива reintroduce в Дельфи

Узнал, что в Дельфи есть директива reintroduce. Она говорит компиляторуо том, что не надо возмущаться, когда в родственных классах определены функции с одинаковыми именами, но разным набором параметров.

Здесь компилятор напомнит, что в коде непорядок:


type TFish = class
  procedure swim(); virtual;
end;

type TBoneFish = class(TFish)
  procedure swim(direction : TVector); overload; // Method 'swim' hides virtual method of base type TFish.
end;

А здесь все стало правильно:


type TFish = class
  procedure swim(); virtual;;
end;

type TBoneFish = class(TFish)
  procedure swim(direction : TVector); reintroduce; overload;
end;

В основном коде можно вызывать оба метода.


  bone_fish.swim(); // куда-то плывем
  bone_fish.swim( to_nutritious_crustacean ); // плывем за питательным рачком

 147   2018   дельфи   программирование

Быстро типографируем текст перед показом на странице

Перед показом текста на странице его надо обработать по правилам типографики. Это может сделать «Типограф» Студии Лебедева, «Типограф» Дениса Селезнева или свой движок.

Если текст написан и не меняется, то его не надо все время типографить. Достаточно оттипографить один раз, сохранить результат и выводить его до тех пор, пока текст снова не изменится.

Для этого использую такой механизм.

  • Создаю исходный текст и сохраняют его в файле с расширением «in».
  • В коде страницы вызываю функцию typo_file( ’имя_файла_с_текстом’ ), которая выводит на страницу оттипографированый текст. Имя файла указывается без расширения.

Функция typo_file( $filename ) делает следующее:

  1. Ищет файл $filename с расширением «in».
  2. Ищет файл с таким же именем и расширением «out».
  3. Сравнивает даты модификации файлов.
  4. Если «out» изменен позже, чем «in», возвращает содержимое «out».
  5. В противном случае типографит содержимое «in», записывает его в «out» и возвращает результат в основной поток.

Код функции typo_file на ПХП:

<?php

function typo_file( $file_name, $input_extension = '.in', $output_extension = '.out' ) {
   if ( !file_exists($file_name.$input_extension) )
      return '';

   $in_time  = filemtime($file_name.$input_extension);
   $out_time = file_exists($file_name.$output_extension) ? filemtime($file_name.$output_extension) : $in_time-1;

   if ($out_time < $in_time) {
      // типографим содержимое файла
      $in_file  = file_get_contents( $file_name.$input_extension );
      $out_file = typo( $in_file );
      // записываем данные в новый файл
      file_put_contents( $file_name.$output_extension, $out_file );
   } else
      $out_file = file_get_contents( $file_name.$output_extension );

   return $out_file;
}
?>

Функция typo типографит текст удобным вам способом.

Содержимое основной страницы выглядит так:

<?php
// …

echo typo_file( ‘page_content’ );

// …
?>

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

 49   2017   прием   программирование   ПХП   типограф