teratail header banner
teratail header banner
質問するログイン新規登録

質問編集履歴

4

正規表現の誤りを修正

2017/09/25 08:23

投稿

workr
workr

スコア158

title CHANGED
File without changes
body CHANGED
@@ -121,7 +121,7 @@
121
121
 
122
122
  function convertToPostfix($expression) {
123
123
  $expression = preg_replace('/\s/', '', $expression);
124
- preg_match_all('/[0-9a-zA-Z-_]+|&&|\|\||\(\)/', $expression, $matches);
124
+ preg_match_all('/[0-9a-zA-Z-_]+|&&|\|\||\(|\)/', $expression, $matches);
125
125
 
126
126
  if(substr_count($expression, '(') !== substr_count($expression, ')')) return false;
127
127
 

3

引数と返り値を変更

2017/09/25 08:23

投稿

workr
workr

スコア158

title CHANGED
File without changes
body CHANGED
@@ -90,8 +90,10 @@
90
90
  var_dump(checkFlags( $expression, $flags ) );
91
91
 
92
92
  function checkFlags($expression, $flags){
93
- $postfix = convertToPostfix($expression, $flags);
93
+ $postfix = convertToPostfix($expression);
94
+
94
-
95
+ $postfix = strtr($postfix, $flags);
96
+
95
97
  $parts = preg_split('/\s/', $postfix, -1, PREG_SPLIT_NO_EMPTY);
96
98
  $stack = [];
97
99
 
@@ -99,8 +101,8 @@
99
101
  if (is_numeric($part)) {
100
102
  $stack[] = $part;
101
103
  } else {
102
- $b = (int)array_pop($stack);
104
+ $b = (float)array_pop($stack);
103
- $a = (int)array_pop($stack);
105
+ $a = (float)array_pop($stack);
104
106
 
105
107
  switch ($part) {
106
108
  case "&&":
@@ -117,12 +119,9 @@
117
119
  return (bool)$stack[0];
118
120
  }
119
121
 
120
- function convertToPostfix($expression, $flags) {
122
+ function convertToPostfix($expression) {
121
123
  $expression = preg_replace('/\s/', '', $expression);
122
- if(substr_count($expression, '(') !== substr_count($expression, ')')) return false;
123
-
124
- $expression = strtr($expression, $flags);
125
- preg_match_all('/[0-9]+|&&|\|\||\(\)/', $expression, $matches);
124
+ preg_match_all('/[0-9a-zA-Z-_]+|&&|\|\||\(\)/', $expression, $matches);
126
125
 
127
126
  if(substr_count($expression, '(') !== substr_count($expression, ')')) return false;
128
127
 
@@ -134,8 +133,18 @@
134
133
  $priorities = [ '&&' => 2, '||' => 2, '(' => 1, ')' => 1 ];
135
134
 
136
135
  foreach ($parts as $part) {
136
+ if( $part == '&&' || $part == '||' ) {
137
- if (is_numeric($part)) {
137
+ if (!empty($stack)) {
138
+ while (true) {
139
+ $end = end($stack);
140
+ if ($end && $priorities[$part] <= $priorities[$end]) {
141
+ $output []= array_pop($stack);
142
+ } else {
143
+ break;
144
+ }
145
+ }
146
+ }
138
- $output[] = $part;
147
+ $stack[] = $part;
139
148
  } elseif ($part == '(') {
140
149
  $stack[] = $part;
141
150
  } elseif ($part == ')') {
@@ -149,18 +158,8 @@
149
158
  }
150
159
  }
151
160
  } else {
152
- if (!empty($stack)) {
153
- while (true) {
154
- $end = end($stack);
155
- if ($end && $priorities[$part] <= $priorities[$end]) {
156
- $output []= array_pop($stack);
161
+ $output[] = $part;
157
- } else {
158
- break;
159
- }
162
+ }
160
- }
161
- }
162
- $stack[] = $part;
163
- }
164
163
  }
165
164
 
166
165
  while (count($stack) > 0) {

2

floatをintに変更

2017/09/14 06:04

投稿

workr
workr

スコア158

title CHANGED
File without changes
body CHANGED
@@ -99,8 +99,8 @@
99
99
  if (is_numeric($part)) {
100
100
  $stack[] = $part;
101
101
  } else {
102
- $b = (float)array_pop($stack);
102
+ $b = (int)array_pop($stack);
103
- $a = (float)array_pop($stack);
103
+ $a = (int)array_pop($stack);
104
104
 
105
105
  switch ($part) {
106
106
  case "&&":

1

解決方法を追記

2017/09/14 05:35

投稿

workr
workr

スコア158

title CHANGED
File without changes
body CHANGED
@@ -63,4 +63,110 @@
63
63
  限られた条件式においては動作しますが、丸括弧が2重になっている場合などでは正しく動作しません。
64
64
  おそらく再帰関数を使わなければならないのだとは思いますが、どのようにすればいいのでしょうか?
65
65
  おかしなやり方をしている部分もあると思いますし、根本的に間違っている場合は全く別のやり方でも構いません。
66
- よろしくお願いします。
66
+ よろしくお願いします。
67
+
68
+
69
+
70
+ ### 追記
71
+
72
+ 2017-09-14
73
+
74
+ shimitei様にコメントで教えていただいた逆ポーランド記法を使いソース全体を作り直しました。
75
+ ひとまず正しく動作できているようなので掲載しておきます。改善点や修正点がありましたらコメントか編集をお願い致します。
76
+
77
+ ```PHP
78
+ <?php
79
+ $flags = [
80
+ 'flag1' => 1,
81
+ 'flag2' => 0,
82
+ 'flag3' => 0,
83
+ 'flag4' => 1,
84
+ 'flag5' => 1
85
+ ];
86
+
87
+ // 「&&」は AND, 「||」 は OR を表す
88
+ $expression = 'flag1 && (flag2 || flag3) || (flag4 && flag5)';
89
+
90
+ var_dump(checkFlags( $expression, $flags ) );
91
+
92
+ function checkFlags($expression, $flags){
93
+ $postfix = convertToPostfix($expression, $flags);
94
+
95
+ $parts = preg_split('/\s/', $postfix, -1, PREG_SPLIT_NO_EMPTY);
96
+ $stack = [];
97
+
98
+ foreach ($parts as $part) {
99
+ if (is_numeric($part)) {
100
+ $stack[] = $part;
101
+ } else {
102
+ $b = (float)array_pop($stack);
103
+ $a = (float)array_pop($stack);
104
+
105
+ switch ($part) {
106
+ case "&&":
107
+ $x = $a && $b;
108
+ array_push($stack, $x);
109
+ break;
110
+ case "||":
111
+ $x = $a || $b;
112
+ array_push($stack, $x);
113
+ }
114
+ }
115
+ }
116
+
117
+ return (bool)$stack[0];
118
+ }
119
+
120
+ function convertToPostfix($expression, $flags) {
121
+ $expression = preg_replace('/\s/', '', $expression);
122
+ if(substr_count($expression, '(') !== substr_count($expression, ')')) return false;
123
+
124
+ $expression = strtr($expression, $flags);
125
+ preg_match_all('/[0-9]+|&&|\|\||\(\)/', $expression, $matches);
126
+
127
+ if(substr_count($expression, '(') !== substr_count($expression, ')')) return false;
128
+
129
+ $parts = $matches[0];
130
+
131
+ $stack = [];
132
+ $output = [];
133
+
134
+ $priorities = [ '&&' => 2, '||' => 2, '(' => 1, ')' => 1 ];
135
+
136
+ foreach ($parts as $part) {
137
+ if (is_numeric($part)) {
138
+ $output[] = $part;
139
+ } elseif ($part == '(') {
140
+ $stack[] = $part;
141
+ } elseif ($part == ')') {
142
+ while (count($stack) > 0) {
143
+ $end = end($stack);
144
+ if ($end == '(') {
145
+ array_pop($stack);
146
+ break;
147
+ } else {
148
+ $output[] = array_pop($stack);
149
+ }
150
+ }
151
+ } else {
152
+ if (!empty($stack)) {
153
+ while (true) {
154
+ $end = end($stack);
155
+ if ($end && $priorities[$part] <= $priorities[$end]) {
156
+ $output []= array_pop($stack);
157
+ } else {
158
+ break;
159
+ }
160
+ }
161
+ }
162
+ $stack[] = $part;
163
+ }
164
+ }
165
+
166
+ while (count($stack) > 0) {
167
+ $output[] = array_pop($stack);
168
+ }
169
+
170
+ return implode(' ', $output);
171
+ }
172
+ ```