Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> [PHP][regexp]Dzielenie wyrażeń arytmetycznych za pomocą wyrażeń regularnych
shinuexx
post
Post #1





Grupa: Zarejestrowani
Postów: 78
Pomógł: 9
Dołączył: 2.02.2011
Skąd: undefined

Ostrzeżenie: (0%)
-----


Witam.
Chciałem sobie zrobić prosty kalkulator który będzie pobierał od użytkownika wyrażenie arytmetyczne i zwracał jego wynik. Np:
Podaję:
Kod
(10+9)/(11*8)

Otrzymuję
Kod
0.215909090

Myślałem nad wykorzystaniem do tego wyrażeń regularnych, ale pojawia się pewien problem. Otóż nie bardzo wiem jak wymusić na kwantyfikatorach, aby dzielił mi wyrażenie tylko względem najwyższego znaku tzn. powyższe wyrażenie powinno mi podzielić na:
Kod
l=(10+9);
r=(11*8);
sign=/;

oczywiście powyższe wyrażenia mogą wyglądać także inaczej. Np można używać na nich prostych funkcji:
Kod
sin(10+4)/cos(8-11)
l=sin(10+4);
sign=/;
r=cos(8-11);

Do tej pory używałem wyrażenia regularnego:
Kod
/^(?<l>[[:print:]]+)(?<sign>[\*\/\-\+]{1})(?<r>[[:print:]]+)/

Każdą ze stron wyrażenia arytmetycznego będę rozpoznawał rekurencyjnie, i do analizy funkcji mam już wyrażenie regularne
Jak można by to najrozsądniej rozwiązać?


Ten post edytował shinuexx 27.11.2011, 14:10:33
Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi
shinuexx
post
Post #2





Grupa: Zarejestrowani
Postów: 78
Pomógł: 9
Dołączył: 2.02.2011
Skąd: undefined

Ostrzeżenie: (0%)
-----


czyli
Cytat
Czyli analizuję ciąg od początku, sprawdzam co mam a potem czego oczekuję następnie. Jeśli tak nie jest to błąd a jeśli jest to następny znak?


Bo jak narazie stworzyłem coś takiego:
  1. <?php
  2.  
  3. /**
  4.  * @author ShInUeXx
  5.  * @copyright 2011
  6.  */
  7.  
  8. class math_exp{
  9.  
  10. /**
  11.   *
  12.   * Typy operatorów
  13.   *
  14.   */
  15. const T_POW="^";
  16. const T_MUL="*";
  17. const T_DIV="/";
  18. const T_ADD="+";
  19. const T_MIN="-";
  20. CONST T_LPAR="(";
  21. CONST T_RPAR=")";
  22. CONST T_FACT="!";
  23.  
  24. const I_NUM=0;
  25. const I_OPR=1;
  26. const I_FUN=2;
  27. const I_VAR=3;
  28.  
  29. private $_opr=array(
  30. self::T_POW,
  31. self::T_MUL,
  32. self::T_DIV,
  33. self::T_ADD,
  34. self::T_MIN,
  35. self::T_FACT,
  36. );
  37.  
  38. private $_allowed_function=array(
  39. "abs",
  40. "acos",
  41. "acosh",
  42. "asin",
  43. "asinh",
  44. "atan2",
  45. "atan",
  46. "atanh",
  47. "ceil",
  48. "cos",
  49. "cosh",
  50. "exp",
  51. "floor",
  52. "fmod",
  53. "log10",
  54. "ln",
  55. "rand",
  56. "round",
  57. "sin",
  58. "sinh",
  59. "sqrt",
  60. "tan",
  61. "tanh",
  62. );
  63.  
  64. private $_vars=array();
  65. private $_token=array();
  66. private $_input;
  67. private $_result=array();
  68. private $_output;
  69.  
  70. public function __construct($vars=array()){
  71. $this->_vars=$vars;
  72. }
  73.  
  74. public function addExp($str){
  75. $this->_input=$str;
  76. }
  77.  
  78. public function addVars($vars){
  79. $this->_vars=array_merge($this->_vars,$vars);
  80. }
  81.  
  82. private function _priority($n){
  83. switch($n){
  84. case self::T_MIN:return 0;break;
  85. case self::T_ADD:return 0;break;
  86. case self::T_DIV:return 1;break;
  87. case self::T_MUL:return 1;break;
  88. case self::T_POW:return 2;break;
  89. case self::T_FACT:return 3;break;
  90. case null:return -1;break;
  91. default:
  92. return getrandmax();
  93. break;
  94. }
  95. }
  96.  
  97. public function countExp($str=null){
  98. if($str===null)$str=$this->_input;
  99. $this->addExp($str);
  100. if(!$this->_lexer()) return false;
  101. $this->_reverse_polish_notation();
  102. $this->_count();
  103. return $this->_output;
  104. }
  105.  
  106. public function _lexer(){
  107. if(!preg_match_all("/([[:digit:]]+[e|E]{1}[\+\-]{0,1}[[:digit:]]+|[A-Za-z]{1}[A-Za-z0-9\_]*|[[:digit:]]+[\.]{0,1}[[:digit:]]*|[\.]{1}[[:digit:]]+|[\!\(\)\+\-\^\/\*\[\]]{1})/",$this->_input,$m))
  108. return false;
  109. $this->_token=$m[0];
  110. return true;
  111. }
  112.  
  113. public function _identify($token){
  114. if(is_numeric($token))
  115. return self::I_NUM;
  116. elseif(in_array($token,($this->_opr)))
  117. return self::I_OPR;
  118. elseif(in_array($token,$this->_allowed_function))
  119. return self::I_FUN;
  120. else
  121. return self::I_VAR;
  122. }
  123.  
  124. public function _reverse_polish_notation(){
  125. $return=&$this->_result;
  126. $token=$this->_token;
  127. $stack=array();
  128. foreach($token as $k=>$v){
  129. $pr=$this->_priority($v);
  130. if($v==self::T_LPAR){
  131. $stack[]=$v;
  132. $sel=1;
  133. }
  134. elseif($v==self::T_RPAR){
  135. $par=array_pop($stack);
  136. while($par!=self::T_LPAR){
  137. $return[]=$par;
  138. $par=array_pop($stack);
  139. }
  140. }
  141. elseif($this->_identify($v)==self::I_NUM||$this->_identify($v)==self::I_VAR){
  142. $return[]=$v;
  143. }
  144. elseif($this->_identify($v)==self::I_OPR||$this->_identify($v)==self::I_FUN){
  145. $last=array_pop($stack);
  146. $T=$this->_priority($last);
  147. if($pr>$T){
  148. if($last!==null) {
  149. $stack[]=$last;
  150. };
  151. $stack[]=$v;
  152. }
  153. elseif($last==self::T_LPAR){
  154. if($v=='-'&&($k==0||$token[$k-1]==self::T_LPAR))$return[]="0";
  155. $stack[]=$last;
  156. $stack[]=$v;
  157. }
  158. else{
  159. if($last!==null&&$last!=self::T_LPAR) $return[]=$last;
  160. $stack[]=$v;
  161. }
  162. }
  163. }
  164. while(!empty($stack))
  165. $return[]=array_pop($stack);
  166.  
  167. }
  168.  
  169. public function _count(){
  170. $vars=$this->_vars;
  171. $rpn=$this->_result;
  172. $stack=array();
  173. foreach($rpn as $v){
  174. switch($this->_identify($v)){
  175. case 0:
  176. $stack[]=$v;
  177. break;
  178. case 1:
  179. switch($v){
  180. case "*":
  181. $b=array_pop($stack);
  182. $a=array_pop($stack);
  183. $stack[]=$a*$b;
  184. break;
  185. case "^":
  186. $b=array_pop($stack);
  187. $a=array_pop($stack);
  188. $stack[]=pow($a,$b);
  189. break;
  190. case "/":
  191. $b=array_pop($stack);
  192. $a=array_pop($stack);
  193. $stack[]=$a/$b;
  194. break;
  195. case "+":
  196. $b=array_pop($stack);
  197. $a=array_pop($stack);
  198. $stack[]=$a+$b;
  199. break;
  200. case "-":
  201. $b=array_pop($stack);
  202. $a=0;
  203. if($this->_identify(end($stack))==0)
  204. $a=array_pop($stack);
  205. $stack[]=$a-$b;
  206. break;
  207. case "!":
  208. $a=array_pop($stack);
  209. $stack[]=factorial($a);
  210. break;
  211. default:
  212.  
  213. break;
  214. }
  215. break;
  216. case 2:
  217. $a=array_pop($stack);
  218. $stack[]=call_user_func($v,$a);
  219. break;
  220. case 3:
  221. $stack[]=$vars[$v];
  222. break;
  223. }
  224. }
  225. $this->_output=array_pop($stack);
  226. }
  227. }
  228.  
  229. ?>


i na większości wyrażeń działa (oczywiście jeszcze błędów nie obsługuje)
Go to the top of the page
+Quote Post

Posty w temacie


Reply to this topicStart new topic
2 Użytkowników czyta ten temat (2 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 13.10.2025 - 22:31