Форум программистов, компьютерный форум, киберфорум
C# Windows Forms
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
0 / 0 / 0
Регистрация: 10.04.2023
Сообщений: 6

Проблемы с кодом для калькулятора со скобками

02.05.2023, 15:15. Показов 408. Ответов 4
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Загвоздка такая, я делал калькулятор со скобками по видео (https://www.youtube.com/watch?v=yJsff4zao3Y&t=3s)
однако человек его не доделал и калькулятор не работает с минусовыми числами
может кто ни будь помочь код дописать так, что бы калькулятор работал нормально?
(попрошу пожалуйста воздержаться от очевидных советов, я новичок в C# и мне проще воспринимать информацию кодом)
или же если у кого ни будь есть ссылка на нормальное видео разработки калькулятора со скобками, то прошу
отправьте мне его пожалуйста.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace PR_10
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private string calc1(string n1, string d, string n2)
        {
            try
            {
                double number1 = Convert.ToDouble(n1);
                double number2 = Convert.ToDouble(n2);
                if (d == "/")
                {
                    if (number2 != 0)
                    {
                        return (number1 / number2).ToString();
                    }
                    else return "err";
                }
                if (d == "*")
                    return (number1 * number2).ToString();
                if (d == "+")
                    return (number1 + number2).ToString();
                if (d == "-")
                    return (number1 - number2).ToString();
            }
            catch(Exception e1)
            {
                return "err";
            }
            return "err";
 
        }
        private string calc(string text)
        {
            listBox1.Items.Clear();
            string tmp="";
            for(int i=0;i<text.Length; i++)
            {
                if (text[i]=='+' || text[i] == '-' || text[i] == '*' || text[i] == '/')
                {
                    listBox1.Items.Add(tmp);
                    listBox1.Items.Add(text[i]);
                    tmp = "";
                }
                else
                {
                    tmp += text[i];
                }
            }
            listBox1.Items.Add(tmp);
 
            for (int i = 0; i< listBox1.Items.Count; i++)
            {
                if (listBox1.Items[i].ToString()=="*" || listBox1.Items[i].ToString() == "/")
                {
                    if(i==0 || i== listBox1.Items.Count -1)
                    {
                        return "err";
 
                    }
                    string res = calc1(listBox1.Items[i-1].ToString(), listBox1.Items[i].ToString(), listBox1.Items[i+1].ToString());
                    if (res == "err") return "err";
                    listBox1.Items.RemoveAt(i - 1);
                    listBox1.Items.RemoveAt(i - 1);
                    listBox1.Items.RemoveAt(i - 1);
                    listBox1.Items.Insert(i-1,res);
                    i--;
                }
            }
 
            for (int i = 0; i < listBox1.Items.Count; i++)
            {
                if (listBox1.Items[i].ToString() == "-" || listBox1.Items[i].ToString() == "+")
                {
                    if (i == 0 || i == listBox1.Items.Count - 1)
                    {
                        return "err";
 
                    }
                    string res = calc1(listBox1.Items[i - 1].ToString(), listBox1.Items[i].ToString(), listBox1.Items[i + 1].ToString());
                    if (res == "err") return "err";
                    listBox1.Items.RemoveAt(i - 1);
                    listBox1.Items.RemoveAt(i - 1);
                    listBox1.Items.RemoveAt(i - 1);
                    listBox1.Items.Insert(i - 1, res);
                    i=0;
                }
            }
            return listBox1.Items[0].ToString();
        }
        private string search(string text)
        {
            bool open = false;
            int open_pos = -1;
            int close_pos = -1;
            bool close = false;
            for (int i = 0; i < text.Length; i++)
            {
                if (text[i] == '(')
                {
                    open = true;
                    open_pos = i;
                }
                if (text[i] == ')')
                {
                    if (open == true)
                    {
                        close = true;
                        close_pos = i;
                        string res = calc(text.Substring(open_pos + 1, close_pos - open_pos-1));
                        text=text.Remove(open_pos, close_pos - open_pos+1);
                        text=text.Insert(open_pos, res);
                        i = 0;
                        open = close = false;
                        close_pos = open_pos = -1;
                    }
                    else
                       return "Ошибка Нет открывающейся скобки!";
                }
            }
            if(open && !close)
            {
                return "Ошибка вы не закрыли скобку!";
            }
            for (int i = 0; i < text.Length; i++)
            {
                if (text[i] == '(')
                {
                    if (text[i] == '(')
                        search(text);
                }
 
            }
            return calc(text);
        }
 
 
        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            textBox2.Text=search(textBox1.Text);
        }
    }
}
Миниатюры
Проблемы с кодом для калькулятора со скобками  
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
02.05.2023, 15:15
Ответы с готовыми решениями:

Проблемы с кодом для ACMP
Помогите пожалуйста. Компилятор не хочет принимать код, хотя подобный код ранее работал using System; namespace Zadacha0061 { ...

Проблемы с кодом для метода простых итераций
Здравствуйте. Работаю над кодом для метода простых итераций. Код взял из методички, переписал в Вольфрам. Но компилятор капризничает. Может...

Проблемы при создании калькулятора
var a,b,c,d,f,l,q: real; e:real; begin writeln('Здраствуйте'); writeln('Выберите, что вы хотите сделать: 1 - сложить, 2 -...

4
Эксперт .NET
 Аватар для Wolfdp
3790 / 1767 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3
02.05.2023, 16:58
Ну... обычно используют Обратная польская запись, которая в свою очередь подразумевает наличие стека. Последнего тут не наблюдается (listBox1.Items вроде просто выводит результат).

В целом вбив в гугл "Обратная польская запись пример C#" можно найти N примеров, включая текущий форум Калькулятор: сделать обратную польскую запись

Анализировать этот код и разбирать желания решительно нет. Могу предложить пример на Console или WPF (либо Forms, но у вас скрее всего слетит разметка и будет все выглядить очень маленьким).

Не по теме:

Цитата Сообщение от antonzen Посмотреть сообщение
есть ссылка на нормальное видео разработки калькулятора со скобками
Это тот самый очевидный совет который вы не просили, но учиться лучше по текстовым ресурсам.



Добавлено через 9 минут
Ну либо если оооочень хочеться в видео формате, то вот https://www.youtube.com/watch?v=UTjI_f1TBUc (хотя, строго говоря, там тоже какой-то ужас).
0
0 / 0 / 0
Регистрация: 10.04.2023
Сообщений: 6
02.05.2023, 17:05  [ТС]
было бы неплохо получить код forms, даже если все будет маленьким
0
Эксперт .NET
 Аватар для Wolfdp
3790 / 1767 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3
03.05.2023, 10:52

Не по теме:

Оказалось что "вроде где-то лежал пример локально" уже не актуально. Пришлось с нуля набрать. Ещё есть чуйка, что все это бесмысленно на 146%. Плак.



Предисловие

Скорее всего код будет не понятен. Это ок. За цель стоит показать как программа должна выглядить более-менее, и какой объем знаний желательно иметь для написания "несчастного калькулятора". Да, можно заговнокодить тупо через if-else с кучей for и возможно goto, оперировать исключительно строками и switch забив на всякие нормы и ООП. Вот только это путь в никуда, потолок с таким подходом -- яндаре симулятор (поищите на том же ютубе как разработчик писал игру своей мечты).


Для начала входную строку нужно раздробить на такие элементы как "число", "скобки", "функция" и "операнд". Для удобства (да, так удобней) для каждого такого элемента создадим record. Алгоритм следующий:
- проходим каждый символ
- если пробел -- игнорим
- если число, начинаем считывать до первого не числового символа (включая точку-разделитель), чтобы понять какую часть парсим как double (смотрим метод NextDouble)
- если литера -- читаем как функцию (пока буква-число, смотрим метод NextFunc). После сверяемся что считаное имя есть в _functions, т.е. ввели валидное имя функции (задаеться в конструкторе)
- если символ -- ищем в операндах, что о таком знаем и его приоритет.

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

Кусок кода отвечающий за это безобразие.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
internal class Parser
{
    private const char ValueSeparator = ',';
    private const char DecimalSeparator = '.';
    private const char OpenParenthesis = '(';
    private const char CloseParenthesis = ')';
    private readonly IReadOnlyDictionary<char, int> _operations;
    private readonly IReadOnlyList<string> _functions;
 
    internal Parser(IEnumerable<(char Key, int Priority)> operations, IEnumerable<string> functions)
    {
        _operations = operations.ToDictionary(x => x.Key, x => x.Priority);
        _functions = functions.ToArray();
    }
 
    //Вот этот метод....
    private IEnumerable<BaseElement> Split(string input)
    {
        var arr = input.ToCharArray();
 
        var index = 0;
        var prevIsDigit = false;
 
        for (; index < arr.Length; index++)
        {
            var c = arr[index];
            if (c == ' ')
            {
                continue;
            }
            else if (c == OpenParenthesis)
            {
                yield return new OpenParenthesisElement();
            }
            else if (c == CloseParenthesis)
            {
                yield return new CloseParenthesisElement();
                prevIsDigit = true;
                continue;
            }
            else if (char.IsDigit(c))
            {
                yield return NextDouble(arr, ref index);
                prevIsDigit = true;
                continue;
            }
            else if (char.IsLetter(c))
            {
                var func = NextFunc(arr, ref index);
                if (!_functions.Contains(func.Name))
                    throw new ParserException($"Unknown function {func.Name}.");
                yield return func;
            }
            else if (c == ValueSeparator)
            {
                yield return new ValueSeparatorElement();
            }
            else if (_operations.TryGetValue(c, out var priority))
            {
                if (c == '-' && !prevIsDigit)
                {
                    yield return new DoubleElement(0);
                    priority = int.MaxValue;
                }
                yield return new OperatorElement(c, priority);
            }
            else
            {
                throw new ParserException("Unknown symbol.");
            }
 
            prevIsDigit = false;
        }
    }
 
    private static DoubleElement NextDouble(char[] input, ref int index)
    {
        int start = index;
        int? end = default;
        while (index < input.Length)
        {
            var c = input[index];
            if (char.IsDigit(c) || c == DecimalSeparator)
            {
                index++;
            }
            else
            {
                end = index--;
                break;
            }
        }
        end ??= input.Length;
        var digital = new string(input, start, end.Value - start);
        if (double.TryParse(digital, CultureInfo.InvariantCulture, out var value))
            return new DoubleElement(value);
        else
            throw new ParserException($"Can't parse value {digital}.");
    }
 
    private static FuncElement NextFunc(char[] input, ref int index)
    {
        int start = index;
        int? end = default;
        while (index < input.Length)
        {
            var c = input[index];
            if (char.IsLetterOrDigit(c))
            {
                index++;
            }
            else
            {
                end = index--;
                break;
            }
        }
        end ??= input.Length;
        var name = new string(input, start, end.Value - start);
        return new FuncElement(name);
    }
 
internal abstract record BaseElement;
internal record OpenParenthesisElement : BaseElement;
internal record CloseParenthesisElement : BaseElement;
internal record DoubleElement(double Value) : BaseElement;
internal record FuncElement(string Name) : BaseElement;
internal record OperatorElement(char Key, int Priority) : BaseElement;
Далее читаем алгоритм сортировочной станции и реализуем тупо как указано.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
    internal IEnumerable<BaseElement> ReversePolishNotation(string input)
    {
        if (string.IsNullOrEmpty(input))
            yield break;
 
        var stack = new Stack<BaseElement>();
 
        foreach (var element in Split(input))
        {
            switch (element)
            { 
                case OpenParenthesisElement openParenthesisElement: 
                    stack.Push(openParenthesisElement);
                    break;
                case CloseParenthesisElement closeParenthesisElement:
                    while (stack.TryPeek(out var op) && op is OperatorElement)
                        yield return stack.Pop();
                    var openBracket = stack.Pop();
                    if (openBracket is not OpenParenthesisElement)
                        throw new ParserException("Parenthesis missing in expression.");
                    if (stack.TryPeek(out var func) && func is FuncElement)
                        yield return stack.Pop();
                    break;
                case DoubleElement doubleElement:
                    yield return doubleElement;
                    break;
                case FuncElement funcElement:
                    stack.Push(funcElement);
                    break;
                case ValueSeparatorElement valueSeparatorElement:
                    while (stack.TryPeek(out var op) && op is OperatorElement)
                        yield return stack.Pop();
                    if (stack.TryPeek(out var next) && next is not OpenParenthesisElement)
                        throw new ParserException("Incorrect use of separator.");
                    break;
                case OperatorElement operatorElement:
                    while (stack.TryPeek(out next)
                        && next is OperatorElement op
                        && op.Priority >= operatorElement.Priority)
                        yield return stack.Pop();
                    stack.Push(operatorElement);
                    break;
            }
        }
 
        while (stack.Count > 0)
        {
            var next = stack.Pop();
            if (next is not OperatorElement)
                throw new ParserException("Incorect expression.");
            yield return next;
        }
    }
Получаем последовательность из элементов, которые уже очень легко обработать используя тот же стек:
- читаем следующий элемент.
- если число -- пихаем в стек
- если функция/операнд, дергаем из стека нужное количество переменых (не забываем про обратную последовательность), вычисляем -- закидываем в стек результат

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
    public double Calculate(string input)
    {
        var stack = new Stack<double>();
        foreach (var item in _parser.ReversePolishNotation(input))
        {
            switch (item)
            {
                case DoubleElement doubleElement:
                    stack.Push(doubleElement.Value);
                    break;
                case OperatorElement @operator:
                    var opResult = _operationHandlers[@operator.Key](stack);
                    stack.Push(opResult);
                    break;
                case FuncElement func:
                    var funcResult = _functionHandlers[func.Name](stack);
                    stack.Push(funcResult);
                    break;
                default:
                    throw new ParserException("Unexpectet exception.");
 
            }
        }
 
        if (stack.Count != 1)
            throw new ParserException("The expression is incorrect.");
 
        return stack.Pop();
    }
по финалу в стеке должен находиться 1 (один) элемент, и не более. Если это не так -- где-то ошибка.

Для удобства (да-да, так удобно. ООП и все такое. Раз полезли сразу кодить в WinForms, то будте добры огребать по полной) все функции и операции упакованы в BaseFunction и BaseOperation. Имея их список можно легко передать их парсеру, а потом через Dictionary применять при вычислении.

Финальный код прилагается, нифига толком не тестировалось, так что вероятность наличия ошибок/недочетев не нулевая.

P.S. на почитать (исходя из вашего "я новичек", допущу что какие-то темы могут быть новые)
- Оператор yield
- Основы LINQ (всю 17 главу)
- ToDictionary
- Обработка исключений (всю 5 главу)
- Типы кортежей
- Все что не ясно -- гуглим!! Вот прям вбиваете лапками "C# %неведомая хрень%", первые два-три результата будут по теме
0
03.05.2023, 10:53

Не по теме:

Итить, кто-то забыл прикрепить файл...

Вложения
Тип файла: zip Calculator.zip (103.9 Кб, 0 просмотров)
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
03.05.2023, 10:53
Помогаю со студенческими работами здесь

Создание калькулятора: проблемы с вычислением (ко)тангенса
Вот описание тригонометрической функции тангенс if (RadioButton1.Checked=True) then ...

Проблемы с кодом
Кто в силах помочь исправить эти чертовы ошибки. Прошу помочь. Пожалуйста.

Проблемы с кодом
Здравствуйте требуется помощь, я как программист мягко говоря не очень, дали задание уже давно написать программу y=sin(x) Код был...

Проблемы с кодом в С++
Я девушка и немного туплю( Можете ли мне помочь написать код? Желательно не сильно мудрено, чтобы я потом разобралась

Проблемы с кодом
У меня при вводе входных данных выдаёт ошибку : free():˽double˽free˽detected˽in˽tcache˽2↵ aborted˽(core˽dumped)↵ вот код Osnova.h ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Новые блоги и статьи
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip. Сканируйте QR-код на мобильном. Вращайте камеру одним пальцем,. . .
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
SDL3 для Web (WebAssembly): Идентификация объектов на Box2D v3 - использование userData и событий коллизий
8Observer8 02.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-collision-events-sdl3-c. zip Сканируйте QR-код на мобильном и вы увидите, что появится джойстик для управления главным героем. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru