1*daf2cd7aSJames Collins<?php 2*daf2cd7aSJames Collins 3*daf2cd7aSJames Collins// @rodneyrehm 4*daf2cd7aSJames Collins// http://stackoverflow.com/a/7917979/99923 5*daf2cd7aSJames Collinsclass ParensParser 6*daf2cd7aSJames Collins{ 7*daf2cd7aSJames Collins // something to keep track of parens nesting 8*daf2cd7aSJames Collins protected $stack = null; 9*daf2cd7aSJames Collins // current level 10*daf2cd7aSJames Collins protected $current = null; 11*daf2cd7aSJames Collins 12*daf2cd7aSJames Collins // input string to parse 13*daf2cd7aSJames Collins protected $string = null; 14*daf2cd7aSJames Collins // current character offset in string 15*daf2cd7aSJames Collins protected $position = null; 16*daf2cd7aSJames Collins // start of text-buffer 17*daf2cd7aSJames Collins protected $buffer_start = null; 18*daf2cd7aSJames Collins 19*daf2cd7aSJames Collins public function parse($string) 20*daf2cd7aSJames Collins { 21*daf2cd7aSJames Collins if (!$string) { 22*daf2cd7aSJames Collins // no string, no data 23*daf2cd7aSJames Collins return array(); 24*daf2cd7aSJames Collins } 25*daf2cd7aSJames Collins 26*daf2cd7aSJames Collins if ($string[0] == '[') { 27*daf2cd7aSJames Collins // killer outer parens, as they're unnecessary 28*daf2cd7aSJames Collins $string = substr($string, 1, -1); 29*daf2cd7aSJames Collins } 30*daf2cd7aSJames Collins 31*daf2cd7aSJames Collins $this->current = array(); 32*daf2cd7aSJames Collins $this->stack = array(); 33*daf2cd7aSJames Collins 34*daf2cd7aSJames Collins $this->string = $string; 35*daf2cd7aSJames Collins $this->length = strlen($this->string); 36*daf2cd7aSJames Collins // look at each character 37*daf2cd7aSJames Collins for ($this->position=0; $this->position < $this->length; $this->position++) { 38*daf2cd7aSJames Collins switch ($this->string[$this->position]) { 39*daf2cd7aSJames Collins case '[': 40*daf2cd7aSJames Collins $this->push(); 41*daf2cd7aSJames Collins // push current scope to the stack an begin a new scope 42*daf2cd7aSJames Collins array_push($this->stack, $this->current); 43*daf2cd7aSJames Collins $this->current = array(); 44*daf2cd7aSJames Collins break; 45*daf2cd7aSJames Collins 46*daf2cd7aSJames Collins case ']': 47*daf2cd7aSJames Collins $this->push(); 48*daf2cd7aSJames Collins // save current scope 49*daf2cd7aSJames Collins $t = $this->current; 50*daf2cd7aSJames Collins // get the last scope from stack 51*daf2cd7aSJames Collins $this->current = array_pop($this->stack); 52*daf2cd7aSJames Collins // add just saved scope to current scope 53*daf2cd7aSJames Collins $this->current[] = $t; 54*daf2cd7aSJames Collins break; 55*daf2cd7aSJames Collins /* 56*daf2cd7aSJames Collins case ' ': 57*daf2cd7aSJames Collins // make each word its own token 58*daf2cd7aSJames Collins $this->push(); 59*daf2cd7aSJames Collins break; 60*daf2cd7aSJames Collins */ 61*daf2cd7aSJames Collins default: 62*daf2cd7aSJames Collins // remember the offset to do a string capture later 63*daf2cd7aSJames Collins // could've also done $buffer .= $string[$position] 64*daf2cd7aSJames Collins // but that would just be wasting resources… 65*daf2cd7aSJames Collins if ($this->buffer_start === null) { 66*daf2cd7aSJames Collins $this->buffer_start = $this->position; 67*daf2cd7aSJames Collins } 68*daf2cd7aSJames Collins } 69*daf2cd7aSJames Collins } 70*daf2cd7aSJames Collins 71*daf2cd7aSJames Collins return $this->current; 72*daf2cd7aSJames Collins } 73*daf2cd7aSJames Collins 74*daf2cd7aSJames Collins protected function push() 75*daf2cd7aSJames Collins { 76*daf2cd7aSJames Collins if ($this->buffer_start !== null) { 77*daf2cd7aSJames Collins // extract string from buffer start to current position 78*daf2cd7aSJames Collins $buffer = substr($this->string, $this->buffer_start, $this->position - $this->buffer_start); 79*daf2cd7aSJames Collins // clean buffer 80*daf2cd7aSJames Collins $this->buffer_start = null; 81*daf2cd7aSJames Collins // throw token into current scope 82*daf2cd7aSJames Collins $this->current[] = $buffer; 83*daf2cd7aSJames Collins } 84*daf2cd7aSJames Collins } 85*daf2cd7aSJames Collins} 86