1

(3 відповідей, залишених у Pascal/Delphi)

Вітаю Незламні! Як виправити помилку "Очікується постійний вираз!" в конструкції Case..Of..Else. Ось метод в якому є конструкція Case..Of..Else:

// Метод повертає позицію оператора найвищого пріорітету в підвиразі, якщо оператор не знайдено повертає 0
Function TOperand.PositionOperator(Const PExpression: String): UInt64;
Begin

  Case True Of
    OperatorInExpression('^', PExpression): Result := PositionInExpression('^', PExpression);
    OperatorInExpression('√', PExpression): Result := PositionInExpression('√', PExpression);
    OperatorInExpression('*', PExpression): Result := PositionInExpression('*', PExpression);
    OperatorInExpression('/', PExpression): Result := PositionInExpression('/', PExpression);
    OperatorInExpression('+', PExpression): Result := PositionInExpression('+', PExpression);
    OperatorInExpression('-', PExpression):
      Begin
        For Var I := 1 To LengthExpression(PExpression) Do
          If (I = 1) And (PExpression[i] = '-') Then
            Continue                      
          Else If  (PExpression[i] = '-') Then
          Begin
            Result := I;           
            Break               
          End

      End
    Else Result := 0
  End

End;

Тут видає помилку що булева функція: OperatorInExpression() не є постійним виразом. Через If..Then..Else все працює, та код погано читабельний:

// Метод повертає позицію оператора найвищого пріорітету в підвиразі, якщо оператор не знайдено повертає 0
Function TOperand.PositionOperator(Const PExpression: String): UInt64;
Begin
  // Якщо жодного оператора не знайдено, повертаємо 0
  Result := 0;

  If OperatorInExpression('^', PExpression) Then
    Result := PositionInExpression('^', PExpression)
  Else If OperatorInExpression('√', PExpression) Then
    Result := PositionInExpression('^', PExpression)
  Else If OperatorInExpression('*', PExpression) Or OperatorInExpression('/', PExpression) Then
  Begin
                                // Від початку виразу і до кінця виразу Виконати
    For Var I := 1 To LengthExpression(PExpression) Do
                        // Якщо символ виразу є оператор '*' Або оператор '/' То
    If (PExpression[i] = '*') Or (PExpression[i] = '/') Then
    Begin
      Result := I;                    // Результату присвоюємо позицію оператора
      Break                                                  // Виходимо з циклу
    End
  End
  Else If OperatorInExpression('+', PExpression) Or OperatorInExpression('-', PExpression) Then
  Begin
                                // Від початку виразу і до кінця виразу Виконати
    For Var I := 1 To LengthExpression(PExpression) Do
    Begin
                                       // Якщо першим символом іде оператор - То
      If (I = 1) And (PExpression[i] = '-') Then
        Continue                       // переходимо до наступної ітерації циклу
                // Інакше, Якщо символ виразу є оператор '+' Або оператор '-' То
      Else
        If (PExpression[i] = '+') Or (PExpression[i] = '-') Then
        Begin
          Result := I;                // Результату присвоюємо позицію оператора
          Break                                              // Виходимо з циклу
        End
    End
  End
End;

Що в такому випадку можна зробити? Переписати через конструкцію If..Then..Else, чи можливо якось виправити помилку в Case..Of..Else?

Реалізація методів OperatorInExpression() та PositionInExpression описана нижче:

           // Метод повертає Істина якшо у виразі знайдено математичний оператор
Function TOperand.OperatorInExpression(Const POperator: WideChar; Const PExpression: String): Boolean;
Begin
  Result := False;

  For Var Op In PExpression Do
    If Op = POperator Then
    Begin
      Result := True;
      Exit
    End

End;

                   // Метод повертає першу позицію підвиразу знайденого в виразі
Function TSystemUtilities.PositionInExpression(Const PSubExpression, PExpression: String): UInt64;
Var
  J: UInt64;       // Лічильники для циклу, визначає поточну позицію в підвиразі
Begin
  Result := 0;                                  // Ініціалізуємо результат нулем

                                     // Пошук першого символу підвиразу в виразі
  For Var I := 1 To LengthExpression(PExpression) Do
  Begin
                  // Якщо символ виразу співпадає з першим символом підвиразу То
    If PExpression[i] = PSubExpression[1] Then
    Begin
                      // Порівнюємо підвираз з виразом, перевіряючи кожен символ
      J := 1;                               // Стаємо на перший символ підвиразу
      // Поки символ підвиразу <= довжини підвиразу І символи виразу та підвиразу співпадають Виконати
      While (J <= LengthExpression(PSubExpression)) And
            (I + J - 1 <= LengthExpression(PExpression)) And // Відповідний символ виразу < за довжину виразу І
            (PExpression[I + J - 1] = PSubExpression[J]) Do // Символи виразу та підвиразу співпадають Виконати
        IncreaseByOne(J);          // Переходимо до наступного символу підвиразу

      // Якщо всі символи підвиразу співпали з виразом То
      If J > LengthExpression(PSubExpression) Then
      Begin
        Result := I; // Повертаємо позицію, з якої починається підвираз у виразі
        Exit;                                              // Виходимо з функції
      End
    End
  End

End;

2

(10 відповідей, залишених у Pascal/Delphi)

leofun01 написав:

Ти певно напхав десятки тисяч ліній коду в 1 файл, чи навіть в 1-у функцію. То ся так не робе.


Для чого це "уточненя" ?

Відповідь не змінилась: пиши в Lazarus.

До чого ваша відповідь? В модулі по 500-700 рядків коду, а навіть якби було більше то що це міняє? А уточнення для того що можливо я нажав якийсь гарячі клавіші випадково, про які я не знаю, от і хочу запитати як виправити це неподобство.

3

(10 відповідей, залишених у Pascal/Delphi)

Вітаю шановне панство! Я користуюся Delphi 11.3 (піратською копією). Сьогодні щось сталося з редактором коду. В одному модулі виділяю і копіюю частину коду та хочу вставити його в інший модуль, а не виходить! Вставляється половина коду функції. Другу половину ніяк не можу скопіювати можете якоюсь порадою допомогти як це виправити.

4

(501 відповідей, залишених у Pascal/Delphi)

Попереднє питання знято. Щоб процедура ComponentsOfNumber правильно заповнювала поля об'єкту TNumber в наступній функції, необхідно змінити тип параметра POperand: TNumber на var.

Procedure ComponentsOfNumber(PNumber: String; Var POperand: TNumber);

5

(501 відповідей, залишених у Pascal/Delphi)

Вітаю панове! Питання: чому не заповняються поля типу TNumber?

В мене є тип:

Type                                                   // Оголошуємо тип - Число
  TNumber = Record
    MathematicalSign: Char;               // Математичний знак числа
    IntegerPartNumber: String;            // Ціла частина числа
    LengthIntegerPartNumber: Cardinal;    // Довжина цілої частини числа
    ComaPosition: Cardinal;               // Позиція коми в числі
    DecimalPartNumber: String;            // Десяткова частина числа
    LengthDecimalPartNumber: Cardinal;    // Довжина десяткової частини числа
    NumberType: String;                   // Тип числа
  End;

Я створив процедуру ComponentsOfNumber:

Procedure ComponentsOfNumber(PNumber: String; POperand: TNumber);
{
Процедура ComponentsOfNumber розбиває число на його компоненти: знак, цілу та
десяткову частини. Знаходить довжину цілої та десяткової частини, а також
визначає яке це число: натуральне, ціле чи дійсне
}
Begin

  If PNumber[1] = '-' Then  // Якщо першим символом операнда являється знак - то
    Begin
      PNumber := AbsoluteValue(PNumber);                 // Видаляємо знак мінус
      POperand.MathematicalSign := '-'       // Ініціалізуємо знак числа в мінус
    End
  Else                                                                 // Інакше
    POperand.MathematicalSign := '+';         // Ініціалізуємо знак числа в плюс

  If Pos(',', PNumber) <> 0 Then                // Якщо в числі присутня кома то
    Begin
      POperand.ComaPosition := Pos(',', PNumber);        // Задаємо позицію коми
                                          // Задаємо довжину цілої частини числа
      POperand.LengthIntegerPartNumber := POperand.ComaPosition - 1;
                                                   // Задаємо цілу частину числа
      POperand.IntegerPartNumber := Copy(PNumber, 1,
                                              POperand.LengthIntegerPartNumber);
                                     // Задаємо довжину десяткової частини числа
      POperand.LengthDecimalPartNumber := Length(PNumber) -
                                                          POperand.ComaPosition;
                                              // Задаємо десяткову частину числа
      POperand.DecimalPartNumber := Copy(PNumber, POperand.ComaPosition + 1,
                                             POperand.LengthDecimalPartNumber)
    End
  Else   // Якщо в числі коми немає
    Begin
      POperand.LengthIntegerPartNumber := Length(PNumber);
      POperand.IntegerPartNumber := PNumber;
      POperand.ComaPosition := 0
    End;

  If Not(POperand.ComaPosition = 0) Then        // Якщо в числі присутня кома то

    If (POperand.MathematicalSign = '-') Then //Якщо в числі присутній знак - то
      POperand.NumberType := 'Дійсне відємне число'   // Число дійсне відємне
    Else                                                               // Інакше
      POperand.NumberType := 'Дійсне додатне число'      // Число дійсне додатне

  Else                                             // Інакше, якщо кома відсутня

    If (POperand.MathematicalSign = '-') Then //Якщо в числі присутній знак - то
      POperand.NumberType := 'Ціле число'     // Число ціле
    Else                                         // Інакше, якщо мінус відсутній
      POperand.NumberType := 'Натуральне число'              // Число натуральне
End;

Я цю процедуру хочу використати в функції Add:

Function Add(PFirstOperand, PSecondOperand: String): String;
                                    // Функція додавання двох раціональних чисел
Var
  I,                                                      // Лічильник для циклу
  LLengthFirstOperand,                         // Кількість цифр першого доданку
  LLengthSecondOperand,                        // Кількість цифр другого доданку
  LLength,                                           // Кількість ітерацій циклу
  LDigitInMemory,                                             // Цифра в пам'яті
  LSum,                       // Сума чисел які додаються у відповідному розряді
  LDigit1, LDigit2: integer;                       // Цифри відповідного розряду

  LNumberOne: TNumber;                                          // Перший операнд
  LNumberTwo: TNumber;                                         // Другий операнд

Begin

          {Розбираємо перший  та другий операнди як число на складові}
  ComponentsOfNumber(PFirstOperand,LNumberOne);
  ComponentsOfNumber(PSecondOperand, LNumberTwo);



// Перевіримо чи заповнені поля!

Result := 'Оп1 Знак: ' + LNumberOne.MathematicalSign +
#13#10 +
'Оп1 Ціла частина: ' + LNumberOne.IntegerPartNumber +
#13#10 +
'Оп1 Довжина цілої частини: ' + IntToStr(LNumberOne.LengthIntegerPartNumber) +
#13#10 +
'Оп1 Позиція коми: ' + IntToStr(LNumberOne.ComaPosition) +
#13#10 +
'Оп1 Десяткова частина: ' + LNumberOne.DecimalPartNumber +
#13#10 +
'Оп1 Довжина десяткової частини: ' + IntToStr(LNumberOne.LengthDecimalPartNumber) +
#13#10 +
'Оп1 Визначення числа: ' + LNumberOne.NumberType +
#13#10 +
'Ціла частина другого операнда: ' + LNumberTwo.IntegerPartNumber;

//  Leveling(LNumberOne, LNumberTwo);
{************************Обробка логіки додавання чисел************************}


{******************************************************************************}



//                                           // знаходимо довжину кожного з рядків
//  LLengthFirstOperand := Length(PFirstOperand);
//  LLengthSecondOperand := Length(PSecondOperand);
//                              // Визначаємо максимальну кількість ітерацій циклу
//  LLength := Maximum(LLengthFirstOperand,LLengthSecondOperand);
//                                                         // Ініціалізуємо змінні
//  LDigitInMemory := 0;
//  Result := '';
//    // Проходимо від кінця до початку кожного рядка та додаємо значення розрядів
//  For I := 1 To LLength Do
//  Begin
//                         // Отримуємо цифру відповідного розряду першого доданку
//    If (I <= LLengthFirstOperand) Then
//      LDigit1 := StrToInt(PFirstOperand[LLengthFirstOperand - I + 1])
//    Else                             // Якщо розряду не існує то присвоюємо нуль
//      LDigit1 := 0;
//                         // Отримуємо цифру відповідного розряду другого доданку
//    If (I <= LLengthSecondOperand) Then
//      LDigit2 := StrToInt(PSecondOperand[LLengthSecondOperand - I + 1])
//    Else                             // Якщо розряду не існує то присвоюємо нуль
//      LDigit2 := 0;
//              //Додаємо відповідні розряди і якщо є, то десятки які були в пам'яті
//    LSum := LDigit1 + LDigit2 + LDigitInMemory;
//       // Якщо результат дорівнює або перевищує 10 то десятки заносимо в пам'ять
//    LDigitInMemory := LSum Div 10;
//                                // У відповідь заносимо остачу від ділення на 10
//    Result := IntToStr(LSum Mod 10) + Result
//  End;
//  // Якщо в пам'яті шились десятки то додаємо їх до відповіді
//  If LDigitInMemory > 0 Then
//    Result := IntToStr(LDigitInMemory) + Result;

End;

І от коли я її перевіряю  виводячи в Мемо1:

procedure TMainForm.Button1Click(Sender: TObject);
var
 Sample: String;
begin
  Sample := 'Проба!';
  Memo1.Lines.Add(Sample);
  Memo1.Lines.Add(Add(Edit2.Text, Edit3.Text));
end;

Мені виводиться якесь сміття яке лежить в пам'яті. Коли я не використовую процедуру ComponentsOfNumber а описую її код прямо в функції Add то все гаразд:

Function Add(PFirstOperand, PSecondOperand: String): String;
                                    // Функція додавання двох раціональних чисел
Var
  I,                                                      // Лічильник для циклу
  LLengthFirstOperand,                         // Кількість цифр першого доданку
  LLengthSecondOperand,                        // Кількість цифр другого доданку
  LLength,                                           // Кількість ітерацій циклу
  LDigitInMemory,                                             // Цифра в пам'яті
  LSum,                       // Сума чисел які додаються у відповідному розряді
  LDigit1, LDigit2: integer;                       // Цифри відповідного розряду

  LNumberOne: TNumber;                                         // Перший операнд
  LNumberTwo: TNumber;                                         // Другий операнд

Begin

          {Розбираємо перший  та другий операнди як число на складові}  

If PFirstOperand[1] = '-' Then  // Якщо першим символом операнда являється знак - то
    Begin
      PFirstOperand := AbsoluteValue(PFirstOperand);                 // Видаляємо знак мінус
      LNumberOne.MathematicalSign := '-'       // Ініціалізуємо знак числа в мінус
    End
  Else                                                                 // Інакше
    LNumberOne.MathematicalSign := '+';         // Ініціалізуємо знак числа в плюс

  If Pos(',', PFirstOperand) <> 0 Then                // Якщо в числі присутня кома то
    Begin
      LNumberOne.ComaPosition := Pos(',', PFirstOperand);        // Задаємо позицію коми
                                          // Задаємо довжину цілої частини числа
      LNumberOne.LengthIntegerPartNumber := LNumberOne.ComaPosition - 1;
                                                   // Задаємо цілу частину числа
      LNumberOne.IntegerPartNumber := Copy(PFirstOperand, 1,
                                              LNumberOne.LengthIntegerPartNumber);
                                     // Задаємо довжину десяткової частини числа
      LNumberOne.LengthDecimalPartNumber := Length(PFirstOperand) -
                                                          LNumberOne.ComaPosition;
                                              // Задаємо десяткову частину числа
      LNumberOne.DecimalPartNumber := Copy(PFirstOperand, LNumberOne.ComaPosition + 1,
                                             LNumberOne.LengthDecimalPartNumber)
    End
  Else   // Якщо в числі коми немає
    Begin
      LNumberOne.LengthIntegerPartNumber := Length(PFirstOperand);
      LNumberOne.IntegerPartNumber := PFirstOperand;
      LNumberOne.ComaPosition := 0
    End;

  If Not(LNumberOne.ComaPosition = 0) Then        // Якщо в числі присутня кома то

    If (LNumberOne.MathematicalSign = '-') Then //Якщо в числі присутній знак - то
      LNumberOne.NumberType := 'Дійсне відємне число'   // Число дійсне відємне
    Else                                                               // Інакше
      LNumberOne.NumberType := 'Дійсне додатне число'      // Число дійсне додатне

  Else                                             // Інакше, якщо кома відсутня

    If (LNumberOne.MathematicalSign = '-') Then //Якщо в числі присутній знак - то
      LNumberOne.NumberType := 'Ціле число'     // Число ціле
    Else                                         // Інакше, якщо мінус відсутній
      LNumberOne.NumberType := 'Натуральне число';              // Число натуральне

  ComponentsOfNumber(PSecondOperand, LNumberTwo);

// Перевіримо чи заповнені поля!

Result := 'Оп1 Знак: ' + LNumberOne.MathematicalSign +
#13#10 +
'Оп1 Ціла частина: ' + LNumberOne.IntegerPartNumber +
#13#10 +
'Оп1 Довжина цілої частини: ' + IntToStr(LNumberOne.LengthIntegerPartNumber) +
#13#10 +
'Оп1 Позиція коми: ' + IntToStr(LNumberOne.ComaPosition) +
#13#10 +
'Оп1 Десяткова частина: ' + LNumberOne.DecimalPartNumber +
#13#10 +
'Оп1 Довжина десяткової частини: ' + IntToStr(LNumberOne.LengthDecimalPartNumber) +
#13#10 +
'Оп1 Визначення числа: ' + LNumberOne.NumberType +
#13#10 +
'Ціла частина другого операнда: ' + LNumberTwo.IntegerPartNumber;
//  Leveling(LNumberOne, LNumberTwo);
{************************Обробка логіки додавання чисел************************}


{******************************************************************************}



//                                           // знаходимо довжину кожного з рядків
//  LLengthFirstOperand := Length(PFirstOperand);
//  LLengthSecondOperand := Length(PSecondOperand);
//                              // Визначаємо максимальну кількість ітерацій циклу
//  LLength := Maximum(LLengthFirstOperand,LLengthSecondOperand);
//                                                         // Ініціалізуємо змінні
//  LDigitInMemory := 0;
//  Result := '';
//    // Проходимо від кінця до початку кожного рядка та додаємо значення розрядів
//  For I := 1 To LLength Do
//  Begin
//                         // Отримуємо цифру відповідного розряду першого доданку
//    If (I <= LLengthFirstOperand) Then
//      LDigit1 := StrToInt(PFirstOperand[LLengthFirstOperand - I + 1])
//    Else                             // Якщо розряду не існує то присвоюємо нуль
//      LDigit1 := 0;
//                         // Отримуємо цифру відповідного розряду другого доданку
//    If (I <= LLengthSecondOperand) Then
//      LDigit2 := StrToInt(PSecondOperand[LLengthSecondOperand - I + 1])
//    Else                             // Якщо розряду не існує то присвоюємо нуль
//      LDigit2 := 0;
//              //Додаємо відповідні розряди і якщо є, то десятки які були в пам'яті
//    LSum := LDigit1 + LDigit2 + LDigitInMemory;
//       // Якщо результат дорівнює або перевищує 10 то десятки заносимо в пам'ять
//    LDigitInMemory := LSum Div 10;
//                                // У відповідь заносимо остачу від ділення на 10
//    Result := IntToStr(LSum Mod 10) + Result
//  End;
//  // Якщо в пам'яті шились десятки то додаємо їх до відповіді
//  If LDigitInMemory > 0 Then
//    Result := IntToStr(LDigitInMemory) + Result;

End;

Підкажіть як вирішити таке питання, бо процедура ComponentsOfNumber потрібна не тільки для функції Add?

6

(501 відповідей, залишених у Pascal/Delphi)

Все знайшов помилку, Result := IntToStr(LOperatorPosition) цей рядок був прописаний в дужках циклу після Break

       //Відповідь обрахунку виразу
Function ExpressionAnswer(PExpression: String): String;
Var
  LBack, LAhead, I: Integer;                                  // Лічильник циклу
//  Operand1, Operand2: String;
  LOperatorPosition: Integer;
  LOperator: Char;                                                   // Оператор
  LDeleteStartPosition, LDeleteEndPosition: Integer; // Позиції видалення виразу
  LFirstOperand, LSecondOperand: Extended;          // Перший та другий операнди

Begin
  Result := '';
  LDeleteStartPosition := 0;
  LDeleteEndPosition := 0;
//      Operand1 := '';
//      Operand2 := '';
  // Від початку і до кінця виразу
  For I := 1 To Length(PExpression) Do
    Begin
                   {Шукаємо з ліва на право множення або ділення}

      If (PExpression[i] = '*') Or (PExpression[i] = '/') Then
        Begin
          if PExpression[i] = '*' then
            LOperator := '*';
          if PExpression[i] = '/' then
            LOperator := '/';
          LOperatorPosition := I;
          Break
        End;

    End;

  Result := IntToStr(LOperatorPosition)+ LOperator;

End;

7

(501 відповідей, залишених у Pascal/Delphi)

koala написав:

Ось цей фрагмент

      If (PExpression[i] = '*') Or (PExpression[i] = '/') Then
        Begin
          If PExpression[i] = '*' Then
            Begin
              LOperator := '*';
              LOperatorPosition := I;
              Break
            End
          Else
            Begin
              LOperator := '/';
              LOperatorPosition := I;
              Break
            End;

        End;
    End;

можна скоротити. Оскільки PExpression[i] або '*', або '/', то можна зробити

LOperator := PExpression[i];

і тоді повністю прибрати внутрішній if:

If (PExpression[i] = '*') Or (PExpression[i] = '/') Then
        Begin
            LOperator := PExpression[i];
            LOperatorPosition := I;
            Break
        End;

Ну і не зрозуміло, нащо перетворювати число на стрічку перед поверненням.

Цей фрагмент навряд чи можна скоротити тому що в виразі який отримує функція в якості рядка може бути вираз: 2563,25*563,06+25,23*37,54/2 і тоді позиція оператора множення береться буде не 8 а 21, а якщо там буде два тири оператора множення. І тоді не буде послідовного виконання операторів.

Мені потрібно послідовно іти з ліва на право виконувати дії.
Першочерговість множення або ділення потім додавання або віднімання.
Тобто функція знайшла оператора перевірила чи це множення чи це ділення (якщо так) виконала витяг числа з права від оператора та з ліва від оператора(мітка закінчення витягу першого операнда або початок рядка або інший оператор, другого операнда або оператор або кінець рядка). Передала числа та оператора в іншу функцію на обрахування. Інша функція повернула результат і цим результатом замінила числа та оператора в рядку які витягувались. І далі знову з ліва на право ітерація чи рекурсія (поки не визначився, тільки почав писати). Якщо множення і ділення немає до кінця рядка то тоді те саме з ліва на право з додаванням і відніманням.
Тобто мені від початку і до кінця рядка потрібно перевірити всі множення і ділення, коли їх не залишиться потрібно перевірити всі додавання і віднімання.

Ось чернетка функції без всяких видалень (тільки начав писати)

Function ExpressionAnswer(PExpression: String): String;
Var
  LBack, LAhead, I: Integer;                                  // Лічильник циклу
//  Operand1, Operand2: String;
  LOperatorPosition: Integer;
  LOperator: Char;                                                   // Оператор
  LDeleteStartPosition, LDeleteEndPosition: Integer; // Позиції видалення виразу
  LFirstOperand, LSecondOperand: Extended;          // Перший та другий операнди

Begin
  I := 1;
  Result := '';
  // Від початку і до кінця виразу
  For I := 1 To Length(PExpression) Do
    Begin

      //Result := '';
      LDeleteStartPosition := 0;
      LDeleteEndPosition := 0;
//      Operand1 := '';
//      Operand2 := '';

                   {Виконуємо з ліва на право множення або ділення}

      If (PExpression[i] = '*') Or (PExpression[i] = '/') Then
        Begin

          If PExpression[i] = '*' Then
            Begin
              LOperator := '*';
              LOperatorPosition := I;



              Result := IntToStr(LOperatorPosition);
              Break
            End
          Else
            Begin
              LOperator := '/';
              LOperatorPosition := I;



              Result := IntToStr(LOperatorPosition);
              Break
            End;

        End;

//                    {Витягуэмо число перед оператором}
//
//          For LBack := (LOperatorPosition - 1) DownTo 1 Do
//            If (PExpression[LBack]= '/') Or (PExpression[LBack]= '+') Or
//                                                  (PExpression[LBack]= '-') Then
//              Break
//            Else
//               LDeleteStartPosition := LBack;
//
//            If PExpression[LBack] <> ' ' Then
//              LFirstOperand := StrToFloat(Copy(PExpression,LBack,(I - 1) - LBack));
//
//                      {Витягуэмо число після оператороа}
//
//          For LAhead := I To Length(PExpression) Do
//            If (PExpression[LBack]= '/') Or (PExpression[LBack]= '+') Or (PExpression[LBack]= '-') Then
//              Break;

    End;
  Result := FloatToStr(LOperatorPosition);
End;

Т справа поки не в оптимізації коду, мене цікавить чому Result := FloatToStr(LOperatorPosition);в коді вище нічого не виводить мені???
А в слідуючому коді Result := FloatToStr(LOperatorPosition); виводить позицію оператора. Де я помилився? Після Break в LOperatorPosition чи в LOperator має ж щось зберігатися? Пробую в Мемо,  що позицію вивести, що LOperator: Char; порожньо!!! Чому???

       //Відповідь обрахунку виразу
Function ExpressionAnswer(PExpression: String): String;
Var
  LBack, LAhead, I: Integer;                                  // Лічильник циклу
//  Operand1, Operand2: String;
  LOperatorPosition: Integer;
  LOperator: Char;                                                   // Оператор
  LDeleteStartPosition, LDeleteEndPosition: Integer; // Позиції видалення виразу
  LFirstOperand, LSecondOperand: Extended;          // Перший та другий операнди

Begin
  I := 1;
  Result := '';
  // Від початку і до кінця виразу
  For I := 1 To Length(PExpression) Do
    Begin

      //Result := '';
      LDeleteStartPosition := 0;
      LDeleteEndPosition := 0;
//      Operand1 := '';
//      Operand2 := '';

                   {Виконуємо з ліва на право множення або ділення}

      If (PExpression[i] = '*') Or (PExpression[i] = '/') Then
        Begin

          If PExpression[i] = '*' Then
            Begin
              LOperator := '*';
              LOperatorPosition := I;
              Result := FloatToStr(LOperatorPosition);


              Result := IntToStr(LOperatorPosition);
              Break
            End
          Else
            Begin
              LOperator := '/';
              LOperatorPosition := I;
              Result := FloatToStr(LOperatorPosition);


              Result := IntToStr(LOperatorPosition);
              Break
            End;

        End;

//                    {Витягуэмо число перед оператором}
//
//          For LBack := (LOperatorPosition - 1) DownTo 1 Do
//            If (PExpression[LBack]= '/') Or (PExpression[LBack]= '+') Or
//                                                  (PExpression[LBack]= '-') Then
//              Break
//            Else
//               LDeleteStartPosition := LBack;
//
//            If PExpression[LBack] <> ' ' Then
//              LFirstOperand := StrToFloat(Copy(PExpression,LBack,(I - 1) - LBack));
//
//                      {Витягуэмо число після оператороа}
//
//          For LAhead := I To Length(PExpression) Do
//            If (PExpression[LBack]= '/') Or (PExpression[LBack]= '+') Or (PExpression[LBack]= '-') Then
//              Break;

    End;

End;

8

(501 відповідей, залишених у Pascal/Delphi)

Вітаю панове. Скажіть будь ласка: Коли застосовувати процедуру Break то після виходу з циклу в змінних нічого не лишається?

Приклад коли виводить функція те що є в змінній, тут Result := IntToStr(LOperatorPosition); пред Break

Function ExpressionAnswer(PExpression: String): String;
Var
  LOperatorPosition: Integer;
  LOperator: Char;                                                   // Оператор
  LDeleteStartPosition, LDeleteEndPosition: Integer; // Позиції видалення виразу
  LFirstOperand, LSecondOperand: Extended;          // Перший та другий операнди

Begin
  I := 1;
  Result := '';

  For I := 1 To Length(PExpression) Do
    Begin

      LDeleteStartPosition := 0;
      LDeleteEndPosition := 0;

                   {Виконуємо з ліва на право множення або ділення}

      If (PExpression[i] = '*') Or (PExpression[i] = '/') Then
        Begin

          If PExpression[i] = '*' Then
            Begin
              LOperator := '*';
              LOperatorPosition := I;



              Result := IntToStr(LOperatorPosition);
              Break
            End
          Else
            Begin
              LOperator := '/';
              LOperatorPosition := I;



              Result := IntToStr(LOperatorPosition);
              Break
            End;

        End;
    End;

End;

А ось тут функція чомусь нічого не виводить коли Result := IntToStr(LOperatorPosition); стоїть після циклу. Чому!!!

Function ExpressionAnswer(PExpression: String): String;
Var
  LOperatorPosition: Integer;
  LOperator: Char;                                                   // Оператор
  LDeleteStartPosition, LDeleteEndPosition: Integer; // Позиції видалення виразу
  LFirstOperand, LSecondOperand: Extended;          // Перший та другий операнди

Begin
  I := 1;
  Result := '';

  For I := 1 To Length(PExpression) Do
    Begin

      LDeleteStartPosition := 0;
      LDeleteEndPosition := 0;

                   {Виконуємо з ліва на право множення або ділення}

      If (PExpression[i] = '*') Or (PExpression[i] = '/') Then
        Begin

          If PExpression[i] = '*' Then
            Begin
              LOperator := '*';
              LOperatorPosition := I;
              Break
            End
          Else
            Begin
              LOperator := '/';
              LOperatorPosition := I;
              Break
            End;

        End;
    End;
  Result := IntToStr(LOperatorPosition);
End;  

9

(501 відповідей, залишених у Pascal/Delphi)

Іще одне питання: про відміну успадкованих методів в класах нащадках.

Якщо в мене є батьківський клас TDefinition в якому є метод SearchInAllDefinition(NameDefi: String);. Він важливий для цього класу так як створений об'єкт на базі цього класу може шукати за допомогою цього методу будь-яке визначення.

  TDefinition = Class

    Strict Private
      ....
      ....
    Private
      ....
      ....
    Protected
      ....
      ....
    Public

      Property Definition: String Read GetDefinition Write SetDefinition;
      Procedure PlayDefinition (Play: Boolean);

      //Метод SearchInAllDefinition в класах нащадках потрібно відмінити
      Procedure SearchInAllDefinition(NameDefi: String);

      Constructor Create; Overload;
      Constructor Create(NameLibSound, NameLibText: PWideChar); Overload;
  End;

Implementation

{ TDefinition }

...
...

End.

Та в класі нащадку він абсолютно не потрібен.

Як мені відмінити цей метод SearchInAllDefinition(NameDefi: String); в класі TNumbers? Щоб при створенні об'єкту на базі класу TNumbers мені не з'являвся після крапки цей метод SearchInAllDefinition. Немає якоїсь директиви для цього? Бо я зробив ось так: прописав такий метод в модифікаторі доступу Private і описав ого в Implementation як пустий метод. І він після цього перестав мені з'являвся після крапки.

Є клас нащадок:

  TNumbers = Class(TDefinition)

    Strict Private
      ....
      ....
    Private
      ....
      Procedure SearchInAllDefinition(NameDefi: String);
    Protected
      ....
      ....
    Public

      
  End;

Implementation

{ TNumbers }
Procedure SearchInAllDefinition(NameDefi: String);
Begin
End;
...
...

End.

10

(501 відповідей, залишених у Pascal/Delphi)

Вітаю панове! Допоможіть написати процедуру (або функцію) яка на вхід буде отримувати масив типу Char, а повертати масив типу Integer.

Спробував ось так:

Procedure TransformArrayCharToDigits(SourceArray: Array Of Char;
                                             Var ReturnArray: Array Of Integer);
Var
  I: Integer;
Begin
  SetLength(ReturnArray, Length(SourceArray));  // Помилка несусні типи

  For I := 0 To Length(SourceArray) Do
    Begin
      If (SourceArray[i] In ['0'..'9']) Then
        Begin
          ReturnArray[i] := StrToInt(SourceArray[i])
        End
    End

End;

виходить помилка несумісні типи.

Спробував іще раз ось так:

Procedure TransformArrayCharToDigits(SourceArray: Array Of Char;
                                           Var ReturnArray: Array Of Integer);
Var
  I: Integer;
  TempArray: Array Of Integer;
Begin
  SetLength(TempArray, Length(SourceArray));

  For I := 0 To Length(SourceArray) Do
    Begin
      If (SourceArray[i] In ['0'..'9']) Then
        Begin
          TempArray[i] := StrToInt(SourceArray[i])
        End
    End;
  ReturnArray := TempArray // Несумісні типи: Масив цілих чисел і Динамічний масив
End;

теж помилка Несумісні типи: Масив цілих чисел і Динамічний масив

11

(501 відповідей, залишених у Pascal/Delphi)

leofun01 написав:

Наявність або відсутність коми в стрічковому представленні числа залежить від локалі середовища. Користуй FormatFloat або FloatToStrF.

s := FormatFloat('0.####', fvalue);

Вибачте пане leofun01, але тут не те! Функція FormatFloat не підходить. Я вже майже доробив процедуру, залишилось задати параметри (Нулі) комі Та десятковій частині числа.

Procedure TNumbers.DeleteZeroInDecimalPartNumber (Number: String);
Begin
  While LengthNumber > ComaPosition - 1 Do
    If Number[High(Number)] <> '0' Then
      Break
    Else
    Begin
      Delete(Number, High(Number), 1);
      fNumberReal := Number;
      SetLengthNumber;
      SetComaPosition;
      SetLengthDecimalPartNumber;
      If Number[High(Number)] = ',' Then
      Begin
        Delete(Number, High(Number), 1);
        fNumberReal := Number;
        SetLengthNumber;
        // Задати позицію коми (в нуль)
        // Задати довжину десяткової частини (в нуль)
      End;
    End
End;

12

(501 відповідей, залишених у Pascal/Delphi)

leofun01 написав:

Repeat _ Until(...) це "повторити _ поки не ...".

Так я вже це зрозумів, тому і питаю алгоритм.

13

(501 відповідей, залишених у Pascal/Delphi)

Бажаю здоров'я панове! Допоможіть скласти алгоритм для вирішення ось такого завдання.

Потрібно прибрати зайві нулі з (числа-рядка). Наприклад, в нас є Змінна типу: String в якій записане будь-яке дійсне число: 123,2500.
Завдання:
Якщо в нас в кінці рядка є нулі (їх може і не бути, а можуть бути і всі нулі після коми), тобто поки High(Number) = '0' то з цього рядка видалити останній символ '0'.
Та потрібно врахувати ще умову, що після коми можуть бути всі нулі, наприклад 123,0000. Тоді потрібно видалити ще і кому з рядка. Лишити тільки 123.

В мене змінна fNumberReal: String; в якій зберігається саме (число-рядок).
Та є, наприклад для (числа - рядка) 123,2500, змінні типу Cardinal, в яких зберігаються:
LengthNumber - Загальна довжина (числа - рядка) 123,2500 = 8;
LengthIntegerPartNumber - Довжина цілої частини (числа - рядка) = 3;
ComaPosition - Позиція коми в (числу - рядку) = 4;
LengthDecimalPartNumber - Довжина десяткової  частини (числа - рядка) = 4;

Я спробував написати процедуру, але в мене чомусь видалило всі символи до коми, лишилось 123,!

Procedure TNumbers.DeleteZeroInDecimalPartNumber (Number: String);
Begin
  While Number[High(Number)] = '0' Do
    Repeat
      Delete(Number, High(Number), 1);
      fNumberReal := Number;
      SetLengthNumber  // Процедура яка задає довжину рядка
    Until (LengthNumber = ComaPosition)
End;

14

(501 відповідей, залишених у Pascal/Delphi)

koala написав:

https://github.com/jrathlev/Delphi-LongInteger ще гляньте

Дякую пане koala. Можливо ви підкажете про функцію яка рахує вирази на кшталт цього (12+30)-7 +(5+2)=. Тобто рахує вираз з дужками. Я десь бачив таку, але вона мені здається була написана чи на JS чи на PHP. коротше в Googl CHROME ця функція є стандартною. Мжливо ви десь натикалися на таку для Delphi?

15

(501 відповідей, залишених у Pascal/Delphi)

koala написав:

А 1/3 як обчислюватимете?

Як і письмово, в стовпчик, періодом. Там треба буде ввести обмеження на період. Над обмеженням я ще поміркую.
В мене буде в модулі об'єкт з полями
1) Для знаку числа
2) Для цілої частини числа
3) Для позиції коми в числі
4) Для десяткової частини числа

То що з масивами? Вірно все з довжиною?

16

(501 відповідей, залишених у Pascal/Delphi)

Ось повний (пробний) модуль і він працює:

unit Unit2;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Menus,
  Vcl.StdCtrls, Vcl.ExtCtrls, System.Math, All_Numbers;

type
  TForm2 = class(TForm)
    Image1: TImage;
    Panel1: TPanel;
    Button1: TButton;
    Edit1: TEdit;
    MainMenu1: TMainMenu;
    N1: TMenuItem;
    Image2: TImage;
    Image3: TImage;
    Image4: TImage;
    Image5: TImage;
    Memo1: TMemo;
    Sound: TCheckBox;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    Procedure InputArrayOfDigit(StrNumber: String);
  end;

var
  Form2: TForm2;
  NumberString: Array Of Char;

implementation

{$R *.dfm}

{Фунція знаходження натурального числа з масиву чисел, яка також не потрібна, бо працює не коректно. Всерівно зявляється Е}
Function StrToNumber (NumStr: Array of Char): Extended;
Var
  I,                                                          // Лічильник циклу
  j: Integer;                                                   // Номер розряду
Begin
  j := 0;                                        // Для j задаємо нульой степінь
  Result := 0;
                                 // Так як сив в нас заповнений з ліва на право,
                                            //а число формується з права на ліво
                          // Для І від найбільшого єлементу масиву до найменшого
  For I := High(NumStr) DownTo Low(NumStr) Do
  Begin
              // Переводимо цифру з тексту в інтежер і множимо на 10 в степені 0
    Result := Result + StrToInt(NumStr[i]) * IntPower(10, j);
    j := j + 1;                                    // Додаємо до степеня одиницю
  End

End;

Procedure TForm2.InputArrayOfDigit(StrNumber: String);
Var
  I,
  dovmas,                                                     // Лічильник для масиву
  NumberOfDigits: Integer;                             // Кількість цифр в числі
Begin
  If StrNumber = '' Then                  // Якщо параметр StrNumber порожній то
    Abort                                                  // виходимо з функції
  Else                                                                 // Інакше
    Begin
      NumberOfDigits := 0;
      dovmas := 0;
      // Визначаємо кількість цифр в параметрі
      NumberOfDigits := Length(StrNumber);
      // Задаємо відповідну довжину динамічного масиву
      SetLength(NumberString, NumberOfDigits);
      dovmas := Length(NumberString);
      // Заповняємо цифрами дин. масив
      For I := 0 To NumberOfDigits Do
        NumberString[i]:= StrNumber[I + 1];
    End;
    Memo1.Lines.Add(IntToStr(NumberOfDigits) + '       // це кількість символів в Edit');
    Memo1.Lines.Add(IntToStr(dovmas) + '       // це довжина масиву');
End;

Function OutputArrayOfDigit(NumStr: Array Of Char): String;
Var
  I: Integer;
Begin
  For I := Low(NumStr) To High(NumStr) Do
    Result := Result + NumStr[i]
End;

procedure TForm2.Button1Click(Sender: TObject);
Var
  Num: TNumbers;
begin
 InputArrayOfDigit(Edit1.Text);
 Memo1.Lines.Add (OutputArrayOfDigit(NumberString) + '       // це те що я ввів в Edit')

end;

procedure TForm2.FormCreate(Sender: TObject);
begin
  Image1.Canvas.Brush.Color := clWhite;
end;

end.

17

(501 відповідей, залишених у Pascal/Delphi)

Гаразд? давайте виведемо перевірку в Memo.
Глобальна змінна:

var
  Form2: TForm2;
  NumberString: Array Of Char;

Ось процедура заповнення масиву (модифікована під Мемо):

Procedure TForm2.InputArrayOfDigit(StrNumber: String);
Var
  I,
  dovmas,                                                     // Лічильник для масиву
  NumberOfDigits: Integer;                             // Кількість цифр в числі
Begin
  If StrNumber = '' Then                  // Якщо параметр StrNumber порожній то
    Abort                                                  // виходимо з функції
  Else                                                                 // Інакше
    Begin
      NumberOfDigits := 0;
      dovmas := 0;
      // Визначаємо кількість цифр в параметрі
      NumberOfDigits := Length(StrNumber);
      // Задаємо відповідну довжину динамічного масиву
      SetLength(NumberString, NumberOfDigits);
      dovmas := Length(NumberString);
      // Заповняємо цифрами дин. масив
      For I := 0 To NumberOfDigits Do
        NumberString[i]:= StrNumber[I + 1];
    End;
    Memo1.Lines.Add(IntToStr(NumberOfDigits) + '       // це кількість символів в Edit');
    Memo1.Lines.Add(IntToStr(dovmas) + '       // це довжина масиву');
End;

А ось функція виводу масиву(для перевірки):

Function OutputArrayOfDigit(NumStr: Array Of Char): String;
Var
  I: Integer;
Begin
  For I := Low(NumStr) To High(NumStr) Do
    Result := Result + NumStr[i]
End;

Клік по кнопці:

procedure TForm2.Button1Click(Sender: TObject);
begin
 InputArrayOfDigit(Edit1.Text);
 Memo1.Lines.Add (OutputArrayOfDigit(NumberString) + '       // це те що я ввів в Edit')

end;

1)Вводжу в Edit 123456
2)Клікаю
3)В Memo виводить:
6             // це кількість символів в Edit
6             // це довжина масиву
123456     // це те що я ввів в Edit


koala написав:

ви плутаєте довжину з номером останнього елемента, причому всюди, де можливо

      NumberOfDigits := Length(Edit1.Text);
      SetLength(NumberString, NumberOfDigits-1);//довжина NumberString на 1 менша, ніж довжина Edit1.Text

Чому тут має бути NumberOfDigits-1??? Якщо функція Length рахує символи в масиві без нульового. В мемо ми це побачили, вивели туди значення NumberOfDigits, воно дорівнює 6. Якщо я ставлю NumberOfDigits-1  в Edit набираю 123456 то виводить:
6       // це кількість символів в Edit
5       // це довжина масиву
12345       // це те що я ввів в Edit
Без одного символу. Куди він дівся?


koala написав:
       For I := 0 To NumberOfDigits Do //цикл повторюється NumberOfDigits+1 разів - на 2 більше, ніж символів у NumberString
      Begin
        NumberString[i]:= Edit2.Text[I+1];//останній символ стрічки копіюється за межі NumberString;
        // остання ітерація бере символ за межами стрічки і пхає його за межі масиву
      End;

Якщо воно його пхає за межі масиву, то чому коли я виводжу функцією OutputArrayOfDigit масив в Мемо мені виводяться усі 6 символів 123456??? Тут поясніть докладніше будь ласка!!!

koala написав:

Вам уже сказали: замініть NumberString з масиву на стрічку; порада про масив була через те, що ви використовували масив стрічок, тобто порадою було замінити String на Char, а масив - це ваша ідея.

Це була хороша порада!

P.S. Масив мені потрібен! Мене вже дістала ця коротка математика в Delphi. Чому діти в п'ятому класі можуть письмово в стовпчик додавати, віднімати, множити і ділити числа будь якої довжини, а тут, коли я обчислюю сталу Планка, вискакує ось така штука 6.62607015E-34. Як мені буде потрібно я напишу функцію для переводу в стандартне число, і заміню Е на 10.
От я вирішив написати (Модуль) функції які будуть працювати як додавання, віднімання і т.д. в стовпчик. Тут мені буде потрібен динамічний масив (я надіюсь він буде безмежної довжини) типу Char та динамічний масив типу Integer для обчислення цілих. І ніяких типів Extended з їхніми 6.62607015E-34.

18

(501 відповідей, залишених у Pascal/Delphi)

koala написав:

Бо початкове значення не задаєте

Function StrToNumber (NumStr: Array of Char): Extended;
Var
  I,                                                          // Лічильник циклу
  j: Integer;                                                   // Номер розряду
Begin
  j := 0;                                        // Для j задаємо нульой степінь
  Result := 0;
                                 // Так як сив в нас заповнений з ліва на право,
                                            //а число формується з права на ліво
                          // Для І від найбільшого єлементу масиву до найменшого
  For I := High(NumStr) DownTo Low(NumStr) Do
  Begin
              // Переводимо цифру з тексту в інтежер і множимо на 10 в степені 0
    Result := Result + StrToInt(NumStr[i]) * IntPower(10, j);
    j := j + 1;                                    // Додаємо до степеня одиницю
  End

End;

Дякую пане koala. Дай боже вам здоров'я і грошей багато. Гарних свят!!!

19

(501 відповідей, залишених у Pascal/Delphi)

koala написав:
Result:=result+...

Ну ось коли вводжу проміжну змінну Num: Extended; то працює:

Var
  I,                                                          // Лічильник циклу
  j: Integer;                                                   // Номер розряду
  Num: Extended;
Begin
  j := 0;                                        // Для j задаємо нульой степінь
  Num := 0;
                                 // Так як сив в нас заповнений з ліва на право,
                                            //а число формується з права на ліво
                          // Для І від найбільшого єлементу масиву до найменшого
  For I := High(NumStr) DownTo Low(NumStr) Do
  Begin
              // Переводимо цифру з тексту в інтежер і множимо на 10 в степені 0
    Num := Num + StrToInt(NumStr[i]) * IntPower(10, j);
    j := j + 1;                                    // Додаємо до степеня одиницю
  End;
  Result := Num
End;

А без неї ніяк. Result:=result+... не працює взагалі чомусь. Щоб не вводити зайву змінну можливо якось рекурсію зробити.
Вибачайте що в свято відбираю у вас час, та можливо порадите щось.

20

(501 відповідей, залишених у Pascal/Delphi)

koala написав:

Тут проблем багато. Почнемо з простого питання: чим саме вас не влаштовує string як тип NumberString?

Вітаю пане koala. Я на початку пробував із типом string там  теж була якась помилка коли виводив масив в memo за допомогою функції OutputArrayOfDigits. Тому за порадою пана Torbins змінив на тип Char. І все запрацювало!

koala написав:

Уважно перевірте параметри циклів. Мабуть, там

For I := 0 To NumberOfDigits-1 Do

Тут я робив раніше ту ж помилку і ви мене виправили В верху цієї сторінки. Тут (напевно) все гаразд так як масив заповнюється. перевірено зворотньою функцією.

koala написав:

І

For I := High(NumStr) DownTo Low(NumStr) Do

Спробував DownTo та ж сама проблема лишилася.

Function StrToNumber (NumStr: Array of Char): Extended;
Var
  I,                                                          // Лічильник циклу
  j: Integer;                                                   // Номер розряду
Begin
  j := 0;                                        // Для j задаємо нульой степінь
                                 // Так як сив в нас заповнений з ліва на право,
                                            //а число формується з права на ліво
                          // Для І від найбільшого єлементу масиву до найменшого
  For I := High(NumStr) DownTo Low(NumStr) Do
  Begin
              // Переводимо цифру з тексту в інтежер і множимо на 10 в степені 0
    Result := StrToInt(NumStr[i]) * IntPower(10, j);
    j := j + 1;                                    // Додаємо до степеня одиницю
  End;
End;

Я думаю помилка десь в тілі циклу ось тут:

For I := High(NumStr) To Low(NumStr) Do
    Begin
              // Переводимо цифру з тексту в інтежер і множимо на 10 в степені 0
      Result := StrToInt(NumStr[i]) * IntPower(10, j);
      j := j + 1;                                  // Додаємо до степеня одиницю
    End;

Та не можу зрозуміти де саме. Думка така що не правильно переводжу тип Char в тип String.

      Result := StrToInt(NumStr[i]) * IntPower(10, j);
      j := j + 1;                                  // Додаємо до степеня одиницю