Задача 8 Урок 21

Урок 21

Напишите функцию, которая получает на вход произвольную строку вида:
5*(3+4)-7*9+3*(2+(2-7))
(арифметическое выражение со скобками любого уровня вложенности и
операциями умножения, вычитания и сложения)
и в качестве ответа возвращает результат этого выражения.
Рекомендация: сначала убедитесь, что число открывающих скобок,
равно числу закрывающих.


 var
   loopCount, count1: integer;
   inputString: string;

function expression(inputString: string): integer;
  var
     loopCount, errorCode: integer;
     stringToInt, lastCh: string;
     flag1, flagChar: boolean;
     newInt1, multInt: integer;

  begin
   //WriteLn('Проверка захода експрешн');
   newInt1 := 0;
   multInt := 0; //число для следующего умножения с newInt1
   expression := 0;
   flagChar := false;
   flag1 := false; //флаг умножения
   stringToInt := ''; // строка для получения числа
   lastCh := '+'; //память на последние + и -
   for loopCount := 1 to length(inputString) do //прохожу по строке
   begin
     //ищу число
     if (inputString[loopCount] >= '0') and (inputString[loopCount] <= '9') then
     begin
         if flagChar and (inputString[loopCount - 1] = '-') then
         begin
            stringToInt := stringToInt + '-' + inputString[loopCount];//если сейчас число, а был минус и флаг не сброшен
            //отправляем строку с минусом в val
            flagChar := false;
         end
         else
            stringToInt := stringToInt + inputString[loopCount]; //добавляю цифру в числовую строку
     end
     else if (inputString[loopCount - 1] = '*') and (inputString[loopCount] <> '*') then
        flagChar := true
     else //если не цифра, а знак
     begin
       //  if not flagChar then
         //begin
            val(stringToInt, newInt1, errorCode); //получаем число из прошлого набора цифр
            stringToInt := '';
            if flag1 then //если проходили знак * перед последним числом
            begin
              newInt1 := newInt1 * multInt;
              flag1 := false;
            end;
            if inputString[loopCount] = '*' then // если сейчас знак *, то запоминаем число
            begin
              multInt := newInt1; //запомнили
              flag1 := true; //надо умножить в след раз
            end
            else //если сейчас не знак умножения,
            // то получаем результат от предыдущего + или -
            begin
              if lastCh = '+' then // +
              begin
                expression := expression + newInt1;
              end
              else // -
              begin
                expression := expression - newInt1;
              end;
              if (inputString[loopCount] = '-') and flag1 then //если сейчас -, а прошлый знак * и умножение не сброшено,
               //то есть число с минусом будет - то мы оставляем +
                 lastCh := '+'
              else
                lastCh := inputString[loopCount]; // если сейчас + или -, то запоминаем
            end;
         //end;
      end;
     end;

       // блок для отработки последнего числа и конечного результата
       val(stringToInt, newInt1, errorCode);
       if flag1 then
       begin
         newInt1 := newInt1 * multInt;
         flag1 := false;
       end;
       if lastCh = '+' then //отработка последнего числа
       begin
         expression := expression + newInt1;
       end
       else
       begin
         expression := expression - newInt1;
       end;
   //writeln('Ответ: ', expression);
 end;


function change(string1: string; loopCount1: integer): string;
  var string2: string;
      loopCount2, count1, fromExpression: integer;

begin
  //WriteLn('Проверка захода чендж');
  count1 := 1;
  string2 := '';
  loopCount2 := loopCount1 + 1;
  while (count1 <> 0) do
  begin
    if (string1[loopCount2] = '(') then
    begin
      inc(count1);
    end
    else if (string1[loopCount2] = ')') then
      count1 := count1 - 1;
    inc(loopcount2);
  end;
  loopCount2 := loopCount2 - 1;
  string2 := Copy(string1, loopCount1 + 1, loopCount2 - loopCount1 - 1);
  Delete(string1,loopCount1, loopCount2 - loopCount1 + 1);

  for loopCount2 := 1 to length(string2) do
  begin
    if string2[loopCount2] = '(' then
      string2 := change(string2, loopCount2);
  end;
  fromExpression :=expression(string2);
  str(fromExpression, string2);
  Insert(string2,string1,loopCount1);
  change := string1;
end;


begin
   count1 := 0;
   writeln('Введите строку');
   // readln(inputString); //закоментил для отладки
   inputString := '5*(3-4)-7*(9-3)*(2*(2-7*(5-9)))';
   writeln('Введенная строка: ', inputString);

  for loopCount := 1 to length(inputString) do
  begin
    if inputString[loopCount] = '(' then
        count1 := count1 + 1
    else if inputString[loopCount] = ')' then
        count1 := count1 - 1;
  end;
  if count1 = 0 then
  begin
    for loopCount := 1 to length(inputString) do
    begin
      if inputString[loopCount] = '(' then
        inputString := change(inputString, loopCount);
    end;
    writeln('Результат: ', expression(inputString));
  end
  else
    writeln('Ошибка: убедитесь, что число открывающих скобок, равно числу закрывающих');
  readln();
end.

КОНСОЛЬ

Введите строку
Введенная строка: 5*(3+4)-7*9+3*(2+(2-7))
Результат: -37
vedro-compota's picture

засчитано

_____________
матфак вгу и остальная классика =)

vedro-compota's picture

Код, предоставленный в вопросе, содержит несколько серьёзных ошибок, которые необходимо
исправить для корректной работы программы. Ниже приведены основные проблемы и предложения
по их исправлению.

---

### **Основные ошибки в коде:**

#### 1. **Некорректная обработка приоритета операций**
Функция `expression` не учитывает порядок выполнения операций (умножение должно
выполняться раньше сложения и вычитания). Это приведёт к неправильным результатам,
например, для выражения `5 + 3 * 4` будет вычислено как `(5 + 3) * 4 = 32`, вместо
правильного `5 + (3 * 4) = 17`.

**Решение:**
Использовать стек для вычисления выражения с приоритетом операций (например, преобразовать
выражение в постфиксную нотацию (Обратная польская запись)).

---

#### 2. **Некорректная обработка отрицательных чисел и минусов**
В коде попытка обработки чисел с минусом не корректна. Например, выражение `5 - (3 + 4)`
может не распознаваться правильно, потому что код не учитывает минус как оператор
вычитания, а не как часть числа.

**Решение:**
Во время разбора строки нужно различать минус как оператор и как часть числа (например,
отрицательное число). Это требует дополнительной логики для определения контекста минуса.

---

#### 3. **Ошибка в переменных: регистр и имена**
В коде используются переменные с разным регистром (например, `loopcount2` и `loopCount2`),
что может вызвать ошибки компиляции в Pascal, где регистр важен. Также, в функции `change`
переменная `loopcount2` используется, но не объявлена.

**Решение:**
Исправить имена переменных на единый стиль (например, `loopCount2`) и убедиться, что все
переменные объявлены.

---

#### 4. **Некорректная обработка скобок**
Функция `change` предназначена для раскрытия скобок, но её реализация может не корректно
обрабатывать вложенные скобки. Например, вложенные скобки могут не заменяться на
результаты вычисления.

**Решение:**
Убедиться, что функция `change` рекурсивно обрабатывает вложенные скобки. Также проверить,
правильно ли заменяется подстрока на результат вычисления.

---

### **Рекомендации по исправлению кода:**

#### **1. Исправление функции `expression` (приоритет операций):**
Вместо текущей реализации, используйте стек или преобразование в постфиксную нотацию.
Пример реализации:

```pascal
function expression(inputString: string): integer;
var
stack: array of char;
i: integer;
num: integer;
op: char;
begin
// Реализация с использованием стека (пример)
// ...
end;
```

---

#### **2. Исправление функции `change` (раскрытие скобок):**
Убедитесь, что функция `change` корректно обрабатывает вложенные скобки. Пример:

```pascal
function change(string1: string; loopCount1: integer): string;
var
count1, loopCount2: integer;
string2: string;
fromExpression: integer;
begin
count1 := 1;
loopCount2 := loopCount1 + 1;
while count1 > 0 do
begin
if string1[loopCount2] = '(' then
inc(count1)
else if string1[loopCount2] = ')' then
dec(count1);
inc(loopCount2);
end;
loopCount2 := loopCount2 - 1;
string2 := Copy(string1, loopCount1 + 1, loopCount2 - loopCount1 - 1);
fromExpression := expression(string2);
Delete(string1, loopCount1, loopCount2 - loopCount1 + 1);
Insert(IntToStr(fromExpression), string1, loopCount1);
change := string1;
end;
```

---

#### **3. Исправление переменных и регистров:**
Убедитесь, что все переменные объявлены и используются с одинаковым регистром. Например,
`loopCount2` вместо `loopcount2`.

---

### **Пример исправленного кода:**

```pascal
function expression(inputString: string): integer;
var
stack: array of char;
i, num: integer;
op: char;
begin
// Реализация с использованием стека и приоритетом операций
// ...
end;

function change(string1: string; loopCount1: integer): string;
var
count1, loopCount2: integer;
string2: string;
fromExpression: integer;
begin
count1 := 1;
loopCount2 := loopCount1 + 1;
while count1 > 0 do
begin
if string1[loopCount2] = '(' then
inc(count1)
else if string1[loopCount2] = ')' then
dec(count1);
inc(loopCount2);
end;
loopCount2 := loopCount2 - 1;
string2 := Copy(string1, loopCount1 + 1, loopCount2 - loopCount1 - 1);
fromExpression := expression(string2);
Delete(string1, loopCount1, loopCount2 - loopCount1 + 1);
Insert(IntToStr(fromExpression), string1, loopCount1);
change := string1;
end;

begin
// Основная часть программы
// ...
end.
```

---

### **Вывод:**
Текущий код имеет серьёзные ошибки, связанные с приоритетом операций, обработкой скобок и
переменными. Для корректной работы программы необходимо:
1. Реализовать вычисление с приоритетом операций.
2. Исправить функцию `change` для корректного раскрытия скобок.
3. Устранить ошибки в переменных и регистре.

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

total duration:       3m53.549099267s
load duration:        2.249687ms
prompt eval count:    2035 token(s)
prompt eval duration: 12.959141s
prompt eval rate:     157.03 tokens/s
eval count:           3855 token(s)
eval duration:        3m40.563585s
eval rate:            17.48 tokens/s

_____________
матфак вгу и остальная классика =)