NotionCommotion Posted October 2, 2014 Share Posted October 2, 2014 I need to parse some text similar to Twig templates, but MUCH more limited and error detection is not required. My reason for not using Twig is Twig seems overkill. All it needs to do is replace variables and simple ternary operators (unlike Twig, the ternary operators use ! instead of "not"). I would welcome any constructive criticism and/or recommended changes on how I implemented it. Thanks <?php date_default_timezone_set('America/Los_Angeles'); ini_set('display_errors', 1); error_reporting(E_ALL); /* Replaces all values surrounded by {{ }} deliminators. Handles direct variable. Multiple variables can be separated by the ~ symbol. Also does (non-nested) ternary operators: x?y, !x?y, x==1?y, x?'y', x?y:z */ $template=' Test1 Hello {{ firstname }} {{ lastname }}. Call me in {{ days_int }} or {{ days_string }} days.<br> Test2 {{ flag_int?"do this2" }}<br> Test3 {{ flag_int?"do this3":"do that3" }}<br> Test4 {{ value_int==5?"do this4" }}<br> Test5 {{ value_int==5?"do this5":"do that5" }}<br> Test6 {{ value_int==4?"do this6" }}<br> Test7 {{ value_int==4?"do this7":"do that7" }}<br> Test8 {{ value_int!=5?"do this8" }}<br> Test9 {{ value_int!=5?"do this9":"do that9" }}<br> Test10 {{ value_int!=4?"do this10" }}<br> Test11 {{ value_int!=4?"do this11":"do that11" }}<br> Test12 {{ value_int!=4 bla "do this12":"do that12" }}<br> Test13 {{ value_int==5?"do this5 to "~firstname:"do that5 to "~firstname }}<br> Test14 {{ !flag_int?"do this14" }}<br> Test15 Hello {{ firstname~" "~lastname~". How are things" }}.<br> '; $values=array( 'firstname'=>'John', 'lastname'=>'Doe', 'days_int'=>5, 'days_string'=>6, 'flag_int'=>true, 'value_int'=>5 ); $parser=new parser(); echo($parser->parse($template,$values)); class parser { public function parse($template,$values) { return preg_replace_callback('/\{\{\ (.+?)\ \}\}/',function ($matches) use ($values) { $ternary = explode("?", $matches[1]); if(count($ternary)>1) { //Ternary operator. $ternary[0] is the condition and $ternary[1] is the resulting value(s) $conditions=explode("==", $ternary[0]); if(count($conditions)>1){ //Equal Condition $cond=($this->getVal($conditions[0],$values)==$this->getVal($conditions[1],$values)); } else { $conditions=explode("!=", $ternary[0]); if(count($conditions)>1){ //Not Equal Condition $cond=!($this->getVal($conditions[0],$values)==$this->getVal($conditions[1],$values)); } else { //A flag $cond=($conditions[0]== "!") ? !($this->getVal(ltrim($conditions[0],'!'),$values)) : ($this->getVal($conditions[0],$values)); } } $options=(explode(':',$ternary[1])); return $cond?$this->getValues($options[0],$values):(isset($options[1])?$this->getValues($options[1],$values):null); } else {return $this->getValues($matches[1],$values);} }, $template); } private function getVal($s,$values) { return in_array($s[0],array('\'','"'))?substr($s,1,strlen($s)-2):(isset($values[$s])?$values[$s]:$s); } private function getValues($strings, $values){ $s=null; foreach(explode('~',$strings) as $string){ $s.=$this->getVal($string,$values); }; return $s; } } ?> Quote Link to comment https://forums.phpfreaks.com/topic/291400-constructive-criticism-on-parsing-text/ Share on other sites More sharing options...
NotionCommotion Posted October 2, 2014 Author Share Posted October 2, 2014 This is going to be more difficult than I thought. Suppose I wish to parse the following JSON where noInvalid is true. { "rules":{ "name":{"required":true,{{ noInvalid?'"noInvalid":true,' }}"maxlength":90,"minlength":2 } } } I am looking for the following, however, my class incorrectly splits on the colon between "noInvalid" and true. Furthermore, the text above is not valid JSON, and is hard to troubleshoot. { "rules":{ "name":{"required":true,"noInvalid":true,"maxlength":90,"minlength":2 } } } I suppose I should either go back to creating it directly from PHP, or maybe get rid of my ternary operator, and go with: { "rules":{ "name":{"required":true,"noInvalid": "{{ noInvalid }}", "maxlength":90,"minlength":2 } } } Problem is to make the original file valid JSON, I need to put quotes around my variables which might cause problems with Boolean values { "rules":{ "name":{"required":true,"noInvalid": "1", "maxlength":90,"minlength":2 } } } Quote Link to comment https://forums.phpfreaks.com/topic/291400-constructive-criticism-on-parsing-text/#findComment-1492564 Share on other sites More sharing options...
NotionCommotion Posted October 3, 2014 Author Share Posted October 3, 2014 Ended up keeping it really simple. Just replace the values. Used "{ }" and '{ }' as a deliminator so it is valid JSON. It will not allow a text value to be parsed in without quotes, so maybe I will add. final public function parse($template, array $values) { //return preg_replace_callback('/\{"{\ (\w+)\ \}\"/',function ($matches) use ($values) { $re = <<<RE / "{ (\w+) }" | '{ (\w+) }' /x RE; return preg_replace_callback($re,function ($matches) use ($values) { if(isset($values[$matches[1]])){ if(is_bool($values[$matches[1]])){$new=($values[$matches[1]]?'true':'false');} elseif(is_numeric($values[$matches[1]])){$new=$values[$matches[1]];} else{$new=$values[$matches[1]];} } else{$new=$matches[0];} return $new; }, $template); } Quote Link to comment https://forums.phpfreaks.com/topic/291400-constructive-criticism-on-parsing-text/#findComment-1492581 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.