Форум программистов, компьютерный форум, киберфорум
Наши страницы
C# Windows Forms
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.88/8: Рейтинг темы: голосов - 8, средняя оценка - 4.88
knyazoleg
0 / 0 / 0
Регистрация: 20.02.2013
Сообщений: 37
1

Парсинг из textBox формул

13.05.2018, 13:31. Просмотров 1624. Ответов 9
Метки нет (Все метки)

Здравствуйте! Есть ли у кого на примете ссылки на примеры/учебники про распарсивание текстовой строки (в которой допустимы, скажем, символы и лексемы x, y, z, ^, +, -, /, SIN, COS, LOG) в формулу-функцию, которая в зависимости от значений параметров будет возвращать необходимое значение.
Заранее спасибо за информацию
0
Лучшие ответы (1)
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
13.05.2018, 13:31
Ответы с готовыми решениями:

Прямой парсинг формул
Написать блок, осуществляющий парсинг формул любого уровня вложенности. Используются круглые...

Загрузка картинок, формул в Rich TextBox с последующим сохранением WORD
Загрузка картинок, формул в Rich TextBox с последующим сохранением WORD. Вставить картинку...

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

Генератор формул, шаблонизатор формул
Всем привет. Не знаю даже как назвать правильно то, что мне нужно, поэтому в инете не могу найти...

Работа с TextBox. Текст из multiline TextBox в несколько простых TextBox
Как перенести большой текст из одного мультилайн textbox в несколько обычных textbox у которых...

9
Fleder
257 / 218 / 108
Регистрация: 09.12.2015
Сообщений: 651
13.05.2018, 13:40 2
knyazoleg, возможно, вашу задачу можно решить динамическим созданием кода.
И, наверное, надо делать замены с помощью регулярок выражений, например, COS(2.1) на Math.Cos(2.1).
0
knyazoleg
0 / 0 / 0
Регистрация: 20.02.2013
Сообщений: 37
13.05.2018, 14:05  [ТС] 3
Не очень представляю, как перестроить ту задачу под эту. К тому же, с регулярками тут все сложно, ибо COS(x) тоже может быть. Делать 2 стека под переменные, символы и группы символов? А как потом вычислять...
0
Fleder
257 / 218 / 108
Регистрация: 09.12.2015
Сообщений: 651
13.05.2018, 15:43 4
Лучший ответ Сообщение было отмечено knyazoleg как решение

Решение

knyazoleg, вы бы привели пример такой строки и того, как вы планируете её использовать потом в программе.

Добавлено через 53 минуты
Цитата Сообщение от knyazoleg Посмотреть сообщение
Не очень представляю, как перестроить ту задачу под эту. К тому же, с регулярками тут все сложно, ибо COS(x) тоже может быть. Делать 2 стека под переменные, символы и группы символов? А как потом вычислять...
Вот пример, использующий код из той темы. Разберётесь?
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
using System;
using System.CodeDom.Compiler;
using System.Text.RegularExpressions;
 
namespace Temp
{
   class Program
   {
      static void Main(string[] args)
      {
         //формула, которую надо преобразовать в метод
         string str = "x + SIN(x) + (y + COS(z)) * LOG(3) - 3.14";
 
         //получает метод из формулы
         //если формула содержит ошибки, то получим null
         Formula f1 = CreateFormula(str);
 
         //вычисляет результат
         double res1 = f1(x: 1, y: 2, z: 3);
 
         Console.ReadKey();
      }
 
      private static Formula CreateFormula(string str)
      {
         string src =
         @"using System;
 
         static class Code
         {
             public static double Formula(double x, double y, double z)
             {
                 return {source};
             }
         }";
         str = Regex.Replace(str.ToLower(), @"[a-z]{3}", x =>
         {
            if(x.Value == "sin") return "Math.Sin";
            if(x.Value == "cos") return "Math.Cos";
            if(x.Value == "log") return "Math.Log";
            return x.Value;
         });
         src = src.Replace("{source}", str);
         var compiler = CodeDomProvider.CreateProvider("C#");
         var result = compiler.CompileAssemblyFromSource(new CompilerParameters(), src);
         if(result.Errors.Count == 0)
         {
            var assembly = result.CompiledAssembly;
            var type = assembly.GetType("Code");
            var method = type.GetMethod("Formula");
            return (Formula)Delegate.CreateDelegate(typeof(Formula), method);
         }
         return null;
      }
 
      public delegate double Formula(double x, double y, double z);
   }
}
Добавлено через 16 минут
Цитата Сообщение от knyazoleg Посмотреть сообщение
символы и лексемы x, y, z, ^, +, -, /,
Правда с символом ^ посложнее будет. В языке C# это оператор логического исключающего ИЛИ.
А если трактовать его как возведение в степень, то надо регулярку изменить под это.
1
knyazoleg
0 / 0 / 0
Регистрация: 20.02.2013
Сообщений: 37
13.05.2018, 16:41  [ТС] 5
Спасибо. Но непонятно, как и что уже в самой программе вызывать определенный исходя из текста в str метод (содержащий формулу) (тут уровень доступа не нужно изменить у Main и заглушки?).
Прога на WinForms, чисто 2 поля textBox1,2 и кнопка. Вводим в строку textBox1 формулу, нажимаем кнопку, в textBox2 выводится та же формула + значение в какой-то точке.

А регулярку просто переопределить чисто для этого символа?

p.s.
Цитата Сообщение от Fleder Посмотреть сообщение
x + SIN(x) + (y + COS(z)) * LOG(3) - 3.14
- этот пример подойдет вполне
0
Fleder
257 / 218 / 108
Регистрация: 09.12.2015
Сообщений: 651
13.05.2018, 16:56 6
Цитата Сообщение от knyazoleg Посмотреть сообщение
Спасибо. Но непонятно, как и что уже в самой программе вызывать определенный исходя из текста в str метод (содержащий формулу) (тут уровень доступа не нужно изменить у Main и заглушки?).
Вам не нужен метод Main (это был лишь пример "напосмотреть").

Для вашей проги для WinForms нужен только метод CreateFormula(...), который вернёт
нужный делегат. Ну и нужен сам делегат Formula.
Всё.
Цитата Сообщение от knyazoleg Посмотреть сообщение
А регулярку просто переопределить чисто для этого символа?
Да не должно быть трудно. Главное со скобками не накосячить, которые там могут быть:
Код
(SIN(x) * COS(y)) ^ (x ^ z)
P.S. Заглушку менять не нужно.
1
knyazoleg
0 / 0 / 0
Регистрация: 20.02.2013
Сообщений: 37
13.05.2018, 18:09  [ТС] 7
Спасибо большое! А можете показать, как делегатом воспользоваться, чтобы вывести результат?
0
Fleder
257 / 218 / 108
Регистрация: 09.12.2015
Сообщений: 651
13.05.2018, 18:32 8
Цитата Сообщение от knyazoleg Посмотреть сообщение
А можете показать, как делегатом воспользоваться, чтобы вывести результат?
Вот пример WinForms программы: knyazoleg.zip
Но там нет проверок на неверные входные данные.
И там символ ^ обрабатывается, как XOR.
0
Рядовой
1037 / 573 / 232
Регистрация: 17.05.2015
Сообщений: 2,246
Завершенные тесты: 1
13.05.2018, 20:35 9
knyazoleg, дык у вас в текстбоксе есть формула, в которую надо подставить параметры, и получить результат?
Вам всего то навсего нужно составить математический анализатор строки.
Анализатор вводимой строки с целью вычислить введенное математическое выражение
0
Fleder
257 / 218 / 108
Регистрация: 09.12.2015
Сообщений: 651
14.05.2018, 00:19 10
knyazoleg, если интересен вариант с формулой, в которой символ ^ интерпретируется,
как возведение в степень:
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
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Text.RegularExpressions;
 
namespace Temp
{
   class Program
   {
      static void Main(string[] args)
      {
         //исходная формула
         string str = "Log(6.6) - (SIN(x + 4.2 - 2) * COS(((y)) / -0.1)) ^ (x ^ z ^ 2,222)";
 
         //конечная формула (после преобразований)
         //этот вид формулы понятен для C#
         string dst;
 
         //делегат, созданный по конечной формуле
         Formula formula = CreateFormula(str, out dst);
 
         Console.ReadKey();
      }
 
      private static Formula CreateFormula(string src, out string dst)
      {
         string code =
         @"using System;
 
         static class Code
         {
             public static double Formula(double x, double y, double z)
             {
                 return {source};
             }
         }";
         string s = @"-?[\d.]+|\#\d+|[a-z]";
         string[] patterns =
         {
            $@"(?<A>sin|cos|log)?\((?:{s})\)",
            $@"({s})\^({s})",
            $@"(?:{s})[*/](?:{s})",
            $@"(?:{s})[+-](?:{s})"
         };
         src = Regex.Replace(src, @"\s+", "").ToLower().Replace(',', '.');
         Dictionary<string, string> dic = new Dictionary<string, string>();
         Func<string, string> f1 = null;
         f1 = s1 =>
         {
            foreach(string p in patterns)
            {
               var m = Regex.Match(s1, p);
               if(m.Success)
               {
                  string value = m.Value;
                  if(m.Groups["A"].Success)
                  {
                     value = value.Replace("sin", "Math.Sin");
                     value = value.Replace("cos", "Math.Cos");
                     value = value.Replace("log", "Math.Log");
                  }
                  if(m.Groups[1].Success && m.Groups[2].Success)
                  {
                     value = $"Math.Pow({m.Groups[1]},{m.Groups[2]})";
                  }
                  string key = $"#{dic.Count}";
                  dic.Add(key, value);
                  string ss = s1.Substring(0, m.Index) + key + s1.Substring(m.Index + m.Length);
                  return f1(ss);
               }
            }
            return s1;
         };
         Func<string, string> f2 = null;
         f2 = s1 =>
         {
            string ss = Regex.Replace(s1, @"\#\d+", x => dic[x.Value]);
            return ss == s1 ? ss : f2(ss);
         };
         dst = f2(f1(src));
         code = code.Replace("{source}", dst);
         var compiler = CodeDomProvider.CreateProvider("C#");
         CompilerParameters parameters = new CompilerParameters();
         parameters.GenerateInMemory = true;
         var result = compiler.CompileAssemblyFromSource(parameters, code);
         if(result.Errors.Count == 0)
         {
            var assembly = result.CompiledAssembly;
            var type = assembly.GetType("Code");
            var method = type.GetMethod("Formula");
            return (Formula)Delegate.CreateDelegate(typeof(Formula), method);
         }
         return null;
      }
 
      public delegate double Formula(double x, double y, double z);
   }
}
0
14.05.2018, 00:19
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
14.05.2018, 00:19

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

Как перенести увеличенные в три раза числа из textBox в другой textBox
Есть два textBox, так вот нужно, записать в первый числа с новой строки, по нажатии на кнопку...

Textbox с длиной в процентах - разъезжается дизайн при большом значении textbox
есть кусок HTML (делается только для IE): &lt;table width=100%&gt; &lt;tr&gt; &lt;td width=234&gt;...&lt;/td&gt; ...

После заполнения TextBox<N> поменять на TextBox<N+1> и предоставить возможность повторного сканирования
Всем привет, Нужна помощь новичку Имею форму с ADODC1 и прикреплены к нему (textbox1 -...


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

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2020, vBulletin Solutions, Inc.