setConfig(array("'","\"") ,"\\", array(" ") ,array(),false,true); // 3. Set the string: $sp->setString("parse me"); // 4. Parse the string with one of the functions, for example parseNextElement() // NOTE: always call setString() or restart after setConfig, or the new specialElements wont be used! // The other vars of the parsing-config can be changed on the fly. // NOTE: the special elements are always case insensitive, and made to UPPERCASE before compared class StringParser { /*********************************** Mebmer Variables ************************************/ // Parsing Config var $quoteChars=array(); // array of 1 char strings with quote chars var $escapeChar=""; // 1 char string whith the escape char var $whitespaceChars=array(); // array of 1 char strings with whitespace chars // whitespaces do split up a String into single Elements. var $specialElements=array(); // array of strings with elements which have to be parsed but are // not in all cases separated trough whitespaces. for example . or > in SQL. // The order of the elements is critical, for example add <= before <, // because else if a <= is in a string, it will be matched as < // ONLY set specialElements if you use the functions parse/peek/skipNextElement() !! var $removeQuotes=false; var $removeEscapeChars=true; // parseNextChar() state vars var $currentPos=-1; // current parsing position (index into workingStr) var $currentChar=""; // current char var $inQuotes=array(); // in which Quotes are we ? var $lastWasEscape=false; // the last parsed char was an escape char var $currentIsEscape=false; // the current char is an escape char var $currentElement=""; // the current element var $elementFinished=false; // contains currentElement a finished element ? // Internal Vars var $originalStr; var $workingStr; var $specialElementsMaxLen=0; var $peekCache=""; // Chache System var $queryIsCached=false; var $queryObjectCache=false; /*********************************** General functions ************************************/ // Constructor function StringParser() { // default config $this->quoteChars=array("'","\""); $this->escapeChar="\\"; $this->whitespaceChars=array(" ","\n","\r","\t"); $this->specialElements=array(); $this->peekCache=""; } // Set's the current parsing configuration // ATTENTION: always call setConfig() before setString() !!! function setConfig( $arrQuoteChars=array("'","\"") , $escapeChar="\\", $arrWhiteSpaceChars=array(" ") , $arrSpecialElements=array(), $removeQuotes=false, $removeEscapeChars=true) { $this->quoteChars=$arrQuoteChars; $this->escapeChar=$escapeChar; $this->whitespaceChars=$arrWhiteSpaceChars; $this->specialElements=$arrSpecialElements; $this->removeQuotes=$removeQuotes; $this->removeEscapeChars=$removeEscapeChars; } // Set's the String which has to be parsed // If you want another parsing-config then the default config, call // setConfig() before setString(), or the specialElements won't be // correctly handled function setString($str) { $this->originalStr=$str; global $QueryCache; // check if in cache $hash = md5($str); if(isset( $QueryCache) && isset($QueryCache[$hash]) && $QueryCache[$hash] !='') { $this->queryIsCached=true; $this->queryObjectCache=unserialize(stripslashes($QueryCache[$hash])); return; }else { $this->queryIsCached=false; } $this->restart(); } // (Re)starts parsing, $workingStr is replaced with $originalStr // calculates specialElementsMaxLen and reset's the parseNextChar() // state vars function restart() { $this->workingStr=$this->originalStr; //calc specialElementsMaxLen $this->specialElementsMaxLen=0; for($i=0;$ispecialElements);++$i) { $len=strlen($this->specialElements[$i]); if($len>$this->specialElementsMaxLen) { $this->specialElementsMaxLen=$len; } } debug_print("specialElementsMaxLen: " . $this->specialElementsMaxLen . "
"); // reset parseNextChar() state vars $this->currentPos=-1; $this->currentChar=""; $this->inQuotes=create_array_fill(count($this->quoteChars), 0); $this->lastWasEscape=false; $this->currentIsEscape=false; $this->currentElement=""; $this->elementFinished=false; $this->peekCache=""; } /*********************************** Parsing functions ************************************/ // parses the next char and appends it to $this->currentElement and updates the // parseNextChar() state vars // returns false if the end of the string is reached, if all went ok true is returned // this function is a helper for all other parsing functions. // use it directly ONLY if you have NO specialElements defined! function parseNextChar() { if(! (++$this->currentPosworkingStr))) return false; $this->currentChar=$this->workingStr{$this->currentPos}; $c=$this->currentChar; debug_print("
"); debug_print("StringParser:: current char: '" . $c . "'
"); // update escape char tracking vars if($this->currentIsEscape) { $this->lastWasEscape=true; $this->currentIsEscape=false; } else { $this->lastWasEscape=false; $this->currentIsEscape=false; } // escape char: if($c==$this->escapeChar) { debug_print("StringParser:: escape char matched: " . $c . "
"); // last was escape: 2 escape chars => the char is used, and the escapement meaning is lost if($this->lastWasEscape) { $this->currentIsEscape=false; $this->lastWasEscape=false; $this->currentElement.=$c; // last was not escape, so the current has escape meaning } else { $this->currentIsEscape=true; // add only if we don't remove escape chars if(!$this->removeEscapeChars) { $this->currentElement.=$c; } } return true; } // handle quote chars (only if the last was no escape char) if(!$this->lastWasEscape) { for($j=0;$jquoteChars);++$j) { if($c==$this->quoteChars[$j]) { // are we in this quotes OR not in other quotes => swap quote var if($this->inQuotes[$j] || is_false(in_array(1,$this->inQuotes))) { $this->inQuotes[$j]= !$this->inQuotes[$j]; // add only if $this->removeQuotes isn't set if(!$this->removeQuotes) { $this->currentElement.=$c; } // else ignore the quotes meaning, but add it anyway } else { $this->currentElement.=$c; } return true; } } } // handle whitespace chars (if we are not in quotes) if(is_false(in_array(1,$this->inQuotes))) { for($j=0;$jwhitespaceChars);++$j) { if($c==$this->whitespaceChars[$j]) { debug_print("StringParser:: whitespace matched: '" . $c . "' nr: " . $j . "
"); // whitespace found, return element if the strlen() is > 0 if(strlen($this->currentElement)>0) { //++$this->currentPos; // skip the whitespace // break all for's an return $element: //break 2; $this->elementFinished=true; return true; } // ignore the whitespace => continue return true; } } } // search for specialElements, but only if we are not in quotes if(is_false(in_array(1,$this->inQuotes))) { $testStr=substr($this->workingStr,$this->currentPos,$this->specialElementsMaxLen); debug_print("StringParser:: testStr is " . $testStr . "
"); if(!is_false($specialElem=array_search_stri_start($testStr,$this->specialElements))) { debug_print("special Element found: " . $specialElem . "
"); // specialElement found! // strlen(element)>0 ? return current element if(strlen($this->currentElement)>0) { debug_print("returning last Element !
"); $this->elementFinished=true; --$this->currentPos; return true; // make the specialElement the current element and return it } else { debug_print("returning specialElement !
"); $this->currentElement=$specialElem; $this->currentPos+=strlen($specialElem); --$this->currentPos; $this->elementFinished=true; return true; } } } // none of the previous tests matches, add the current char to the element debug_print("StringParser:: normal char...
"); $this->currentElement.=$c; return true; } // function // returns the next Element and remove's it function parseNextElement() { if(!is_empty_str($this->peekCache)) { debug_print("StringParser:: cache hit for " . $this->peekCache . "
"); $tmp=$this->peekCache; $this->peekCache=""; return $tmp; } $this->currentElement=""; while($this->parseNextChar() && !$this->elementFinished) { } debug_print( "StringParser:: workingStr before: '" . $this->workingStr . "'
"); // remove $this->workingStr=substr($this->workingStr,$this->currentPos); debug_print( "StringParser:: workingStr after: '" . $this->workingStr . "'
"); debug_print( "StringParser:: returning Element: '" . $this->currentElement . "'
"); $this->currentPos=0; $this->elementFinished=false; return $this->currentElement; } // function // returns the next Element but doesn't remove it function peekNextElement() { if(!is_empty_str($this->peekCache)) { debug_print("StringParser:: cache hit for " . $this->peekCache . "
"); return $this->peekCache; } $this->peekCache=$this->parseNextElement(); return $this->peekCache; } // skips the next Element function skipNextElement() { if(!is_empty_str($this->peekCache)) { debug_print("StringParser:: nothing to skip, erasing cache...
"); $this->peekCache=""; return; } $this->parseNextElement(); } // parses the next Elements until $separatorElement or one of the $finishElements // it found. // The parsed values are returned in the array $arrParsedElements // Returns true if elements were parsed, else false is returned function parseNextElements($separatorElement,$finishElements, &$arrParsedElements) { $arrParsedElements=array(); while($elem=$this->peekNextElement()) { if(strtoupper($elem)==strtoupper($separatorElement)) { $this->skipNextElement(); break; } for($i=0;$iskipNextElement(); } if(count($arrParsedElements)>0) return true; return false; } /*********************************** Replace functions ************************************/ // returns a String where $searchChar is replaced with replaceStr, // expect places where $searchChar is escaped // make sure that NO specialElements are set, else this function will not work correctly. function replaceCharWithStr($searchChar,$replaceStr) { $this->restart(); $resStr=""; while($this->parseNextChar()) { $c=$this->currentChar; if($searchChar==$c && !$this->lastWasEscape) { $resStr.= $replaceStr; } else { $resStr .= $c; } } return $resStr; } /*********************************** Split functions ************************************/ // returns an array with the splitted strings. // The specialElements are used to split the string up. // You may also define quoteChars and escapeChar so no specielElements // in Quotes are used. But do NOT set any whitespaceChars! function splitWithSpecialElements() { $arr=array(); $arrPos=0; while($elem=$this->parseNextElement()) { $isSpecial=false; debug_print("splitWithSpecialElements elem: " . $elem . "
"); for($i=0;$ispecialElements);++$i) { if(strtoupper($elem)==strtoupper($this->specialElements[$i])) { $isSpecial=true; break; } } if($isSpecial) { $arr[++$arrPos]=""; } else { if(!isset($arr[$arrPos])) // pos 0 bugfix... $arr[$arrPos]=""; $arr[$arrPos].=$elem; } } return $arr; } // same as splitWithSpecialElements, but you have to pass an array // as parameter, which is filled with the specialElements which // where found in the string and used to split (all are in UPPERCASES). function splitWithSpecialElementsRetUsed(&$arrUsedSpecElements) { $arr=array(); $arrPos=0; while($elem=$this->parseNextElement()) { $isSpecial=false; debug_print("splitWithSpecialElementsRetUsed elem: " . $elem . "
"); for($i=0;$ispecialElements);++$i) { if(strtoupper($elem)==strtoupper($this->specialElements[$i])) { $isSpecial=true; if(!in_array(strtoupper($this->specialElements[$i]),$arrUsedSpecElements)) { $arrUsedSpecElements[]=strtoupper($this->specialElements[$i]); } break; } } if($isSpecial) { $arr[++$arrPos]=""; } else { if(!isset($arr[$arrPos])) // pos 0 bugfix... $arr[$arrPos]=""; $arr[$arrPos].=$elem; } } return $arr; } } ?>