Regular Expressions 101

Save & Share

Flavor

  • PCRE2 (PHP >=7.3)
  • PCRE (PHP <7.3)
  • ECMAScript (JavaScript)
  • Python
  • Golang
  • Java 8
  • .NET 7.0 (C#)
  • Rust
  • Regex Flavor Guide

Function

  • Match
  • Substitution
  • List
  • Unit Tests

Tools

Sponsors
There are currently no sponsors. Become a sponsor today!
An explanation of your regex will be automatically generated as you type.
Detailed match information will be displayed here automatically.
  • All Tokens
  • Common Tokens
  • General Tokens
  • Anchors
  • Meta Sequences
  • Quantifiers
  • Group Constructs
  • Character Classes
  • Flags/Modifiers
  • Substitution
  • A single character of: a, b or c
    [abc]
  • A character except: a, b or c
    [^abc]
  • A character in the range: a-z
    [a-z]
  • A character not in the range: a-z
    [^a-z]
  • A character in the range: a-z or A-Z
    [a-zA-Z]
  • Any single character
    .
  • Alternate - match either a or b
    a|b
  • Any whitespace character
    \s
  • Any non-whitespace character
    \S
  • Any digit
    \d
  • Any non-digit
    \D
  • Any word character
    \w
  • Any non-word character
    \W
  • Match everything enclosed
    (?:...)
  • Capture everything enclosed
    (...)
  • Zero or one of a
    a?
  • Zero or more of a
    a*
  • One or more of a
    a+
  • Exactly 3 of a
    a{3}
  • 3 or more of a
    a{3,}
  • Between 3 and 6 of a
    a{3,6}
  • Start of string
    ^
  • End of string
    $
  • A word boundary
    \b
  • Non-word boundary
    \B

Regular Expression

/
/
ixgms

Test String

Code Generator

Generated Code

#include <StringConstants.au3> ; to declare the Constants of StringRegExp #include <Array.au3> ; UDF needed for _ArrayDisplay and _ArrayConcatenate Local $sRegex = "(?ixms)(\s+)(?:abstract\s+|final\s+|private\s+|protected\s+|public\s+)?(?:static\s+)?(function)\s+(\w+)\s*(\((?>[^()]+|(?R))*\))|({(?>[^{}]+|(?R))*})" Local $sString = "<?php declare(strict_types=1);" & @CRLF & _ "" & @CRLF & _ "namespace PHPAstVisualizer;" & @CRLF & _ "" & @CRLF & _ "use phpDocumentor\GraphViz\Edge as GraphEdge;" & @CRLF & _ "use phpDocumentor\GraphViz\Graph;" & @CRLF & _ "use phpDocumentor\GraphViz\Node as GraphNode;" & @CRLF & _ "" & @CRLF & _ "class Options {" & @CRLF & _ " private $options = [" & @CRLF & _ " 'graph' => []," & @CRLF & _ " 'node' => ['shape' => 'rect']," & @CRLF & _ " 'edge' => []," & @CRLF & _ " 'childEdge' => ['style' => 'dashed','arrowhead' => 'empty']," & @CRLF & _ " ];" & @CRLF & _ " private $name;" & @CRLF & _ "}" & @CRLF & _ "" & @CRLF & _ " public function __construct(string $name, array $options = []) {" & @CRLF & _ " $this->name = $name;" & @CRLF & _ " $this->graphOptions = array_merge($this->options, $options);" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " public function getName(): string {" & @CRLF & _ " return $this->name;" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " public function graph(Graph $graph) {" & @CRLF & _ " foreach ($this->options['graph'] as $name => $value) {" & @CRLF & _ " $graph->{'set' . $name}($value);" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " public function node(GraphNode $node) {" & @CRLF & _ " foreach ($this->options['node'] as $name => $value) {" & @CRLF & _ " $node->{'set' . $name}($value);" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " public function childEdge(GraphEdge $edge) {" & @CRLF & _ " $this->edge($edge);" & @CRLF & _ " foreach ($this->options['childEdge'] as $name => $value) {" & @CRLF & _ " $edge->{'set' . $name}($value);" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " public function edge(GraphEdge $edge) {" & @CRLF & _ " foreach ($this->options['edge'] as $name => $value) {" & @CRLF & _ " $edge->{'set' . $name}($value);" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ "}" & @CRLF & _ " /**" & @CRLF & _ " * PHP file with an autoload function which will be included into the" & @CRLF & _ " * sandbox of the InstantSVC CodeAnalyzer" & @CRLF & _ " * @var string" & @CRLF & _ " */" & @CRLF & _ " protected $autoloadFile = '';" & @CRLF & _ "" & @CRLF & _ " /**" & @CRLF & _ " * Sets the output driver and initializes" & @CRLF & _ " * @param CallgraphDriver $driver output driver to use" & @CRLF & _ " * @return PHPCallGraph" & @CRLF & _ " */" & @CRLF & _ " public function __construct(CallgraphDriver $driver = null) {" & @CRLF & _ " if ($driver != null) {" & @CRLF & _ " $this->driver = $driver;" & @CRLF & _ " } else {" & @CRLF & _ " $this->driver = new TextDriver();" & @CRLF & _ " }" & @CRLF & _ " $functions = get_defined_functions();" & @CRLF & _ " $this->internalFunctions = $functions['internal'];" & @CRLF & _ " // List of PHP keywords which could be followed by an opening parenthis" & @CRLF & _ " // taken from PHP Manual (http://www.php.net/reserved_keywords)" & @CRLF & _ " $this->internalKeywords = array(" & @CRLF & _ " 'array', 'declare', 'die', 'echo', 'elseif', 'empty', 'eval'," & @CRLF & _ " 'exit', 'for', 'foreach', 'global', 'if', 'include', 'include_once'," & @CRLF & _ " 'isset', 'list', 'print', 'require', 'require_once', 'return'," & @CRLF & _ " 'switch', 'unset', 'while', 'catch', 'or', 'and', 'xor', 'new Exception');" & @CRLF & _ " $this->constants = array_keys(get_defined_constants());" & @CRLF & _ "" & @CRLF & _ " //TODO: provide setter for this" & @CRLF & _ " //$this->ignoreList = array('PHPCallGraph::setDriver', 'PHPCallGraph::__construct', 'PHPCallGraph::setShowExternalCalls', 'PHPCallGraph::setShowInternalFunctions', 'PHPCallGraph::save', 'PHPCallGraph::__toString');" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " public function setDriver(CallgraphDriver $driver = null) {" & @CRLF & _ " if ($driver != null) {" & @CRLF & _ " $this->driver = $driver;" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " /**" & @CRLF & _ " * Enable or disable printing of debug information" & @CRLF & _ " * @param boolean $enabled" & @CRLF & _ " */" & @CRLF & _ " public function setDebug($enabled = true) {" & @CRLF & _ " $this->debug = $enabled;" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " protected function debug($string) {" & @CRLF & _ " if ($this->debug) {" & @CRLF & _ " print "||PHPCallGraph| ".$string."\n";" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " protected function info($string) {" & @CRLF & _ " if ($this->showInfo) {" & @CRLF & _ " print "||PHPCallGraph| ".$string."\n";" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " protected function warning($string) {" & @CRLF & _ " if ($this->showWarnings) {" & @CRLF & _ " print "||PHPCallGraph* *WARNING* ".$string."\n";" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ "" & @CRLF & _ " /**" & @CRLF & _ " * Sets a PHP file with an autoload function which will be included into" & @CRLF & _ " * the sandbox of the InstantSVC CodeAnalyzer" & @CRLF & _ " * @param string $filename Name of a PHP file with an autoload function" & @CRLF & _ " * @return boolean success" & @CRLF & _ " */" & @CRLF & _ " public function setAutoloadFile($filename) {" & @CRLF & _ " $returnValue = false;" & @CRLF & _ " if (!empty($filename) and is_file($filename) and is_readable($filename)) {" & @CRLF & _ " $this->autoloadFile = $filename;" & @CRLF & _ " $returnValue = true;" & @CRLF & _ " } else {" & @CRLF & _ " //TODO: throw exception" & @CRLF & _ " }" & @CRLF & _ " return $returnValue;" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " public function setShowExternalCalls($boolean = true) {" & @CRLF & _ " $this->showExternalCalls = $boolean;" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " public function setShowInternalFunctions($boolean = true) {" & @CRLF & _ " $this->showInternalFunctions = $boolean;" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " public function collectFileNames(array $filesOrDirs, $recursive = false) {" & @CRLF & _ " $files = array();" & @CRLF & _ " foreach ($filesOrDirs as $fileOrDir) {" & @CRLF & _ " if (is_file($fileOrDir)) {" & @CRLF & _ " $files[] = $fileOrDir;" & @CRLF & _ " } elseif (is_dir($fileOrDir)) {" & @CRLF & _ " $globbed = glob("$fileOrDir/*");" & @CRLF & _ " if ($recursive) {" & @CRLF & _ " $files = array_merge($files, $this->collectFileNames($globbed, true));" & @CRLF & _ " } else {" & @CRLF & _ " foreach($globbed as $path) {" & @CRLF & _ " if (is_file($path)) {" & @CRLF & _ " $files[] = $path;" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ " return $files;" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " public function parse(array $filesOrDirs, $recursive = false) {" & @CRLF & _ " $files = $this->collectFileNames($filesOrDirs, $recursive);" & @CRLF & _ " if ($this->debug) {" & @CRLF & _ " var_dump($files);" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " $ca = new iscCodeAnalyzer(null);" & @CRLF & _ " $ca->setDebug($this->debug);" & @CRLF & _ " $ca->setAutoloadFile($this->autoloadFile);" & @CRLF & _ " $ca->inspectFiles($files);" & @CRLF & _ " $this->codeSummary = $ca->getCodeSummary();" & @CRLF & _ " $this->analyseCodeSummary();" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " public function parseFile($file) {" & @CRLF & _ " $ca = new iscCodeAnalyzer(null);" & @CRLF & _ " $ca->setDebug($this->debug);" & @CRLF & _ " $ca->setAutoloadFile($this->autoloadFile);" & @CRLF & _ " $ca->inspectFiles(array($file));" & @CRLF & _ " $this->codeSummary = $ca->getCodeSummary();" & @CRLF & _ " $this->analyseCodeSummary();" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " public function parseDir($dir = '.') {" & @CRLF & _ " $ca = new iscCodeAnalyzer($dir);" & @CRLF & _ " $ca->setDebug($this->debug);" & @CRLF & _ " $ca->setAutoloadFile($this->autoloadFile);" & @CRLF & _ " $ca->collect();" & @CRLF & _ " $this->codeSummary = $ca->getCodeSummary();" & @CRLF & _ " $this->analyseCodeSummary();" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " public function analyseCodeSummary() {" & @CRLF & _ " $this->buildLookupTables();" & @CRLF & _ "" & @CRLF & _ " //TODO: analyze code in the global scope" & @CRLF & _ " // currently a workarround is to manually wrap such code" & @CRLF & _ " // in a dummy function called dummyFunctionForFile_filename_php()" & @CRLF & _ "" & @CRLF & _ " // analyze functions" & @CRLF & _ " if (!empty($this->codeSummary['functions'])) {" & @CRLF & _ " foreach ($this->codeSummary['functions'] as $functionName => $function) {" & @CRLF & _ " $this->parseMethodBody(" & @CRLF & _ " '-'," & @CRLF & _ " $functionName," & @CRLF & _ " array()," & @CRLF & _ " array()," & @CRLF & _ " $function['file']," & @CRLF & _ " $function['startLine']," & @CRLF & _ " $function['endLine']" & @CRLF & _ " );" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " // analyze classes" & @CRLF & _ " if (!empty($this->codeSummary['classes'])) {" & @CRLF & _ " foreach ($this->codeSummary['classes'] as $className => $class) {" & @CRLF & _ " /*" & @CRLF & _ " echo $className, "\n";" & @CRLF & _ " var_export($class);" & @CRLF & _ " echo "\n\n";" & @CRLF & _ " //*/" & @CRLF & _ " if (!empty($class['methods'])) {" & @CRLF & _ " $propertyNames = array_keys($class['properties']);" & @CRLF & _ " $methodNames = array_keys($class['methods']);" & @CRLF & _ " //var_export($propertyNames);" & @CRLF & _ " //var_export($methodNames);" & @CRLF & _ " foreach ($class['methods'] as $methodName => $method) {" & @CRLF & _ " $this->parseMethodBody(" & @CRLF & _ " $className," & @CRLF & _ " $methodName," & @CRLF & _ " $propertyNames," & @CRLF & _ " $methodNames," & @CRLF & _ " $class['file']," & @CRLF & _ " $method['startLine']," & @CRLF & _ " $method['endLine']" & @CRLF & _ " );" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " protected function buildLookupTables() {" & @CRLF & _ " if (!empty($this->codeSummary['classes'])) {" & @CRLF & _ " foreach ($this->codeSummary['classes'] as $className => $class) {" & @CRLF & _ " //currently unused" & @CRLF & _ " /*" & @CRLF & _ " if (!empty($class['properties'])) {" & @CRLF & _ " foreach ($class['properties'] as $propertyName => $property) {" & @CRLF & _ " $this->propertyLookupTable[$propertyName][] = $className;" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ " //*/" & @CRLF & _ " if (!empty($class['methods'])) {" & @CRLF & _ " foreach ($class['methods'] as $methodName => $method) {" & @CRLF & _ " $this->methodLookupTable[$methodName][] = $className;" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " /**" & @CRLF & _ " * @param string $className" & @CRLF & _ " * @param string $methodName" & @CRLF & _ " * @param array $propertyNames" & @CRLF & _ " * @param array $methodNames" & @CRLF & _ " * @param string $file" & @CRLF & _ " * @param integer $startLine" & @CRLF & _ " * @param integer $endLine" & @CRLF & _ " */" & @CRLF & _ " public function parseMethodBody(" & @CRLF & _ " $className," & @CRLF & _ " $methodName," & @CRLF & _ " Array $propertyNames," & @CRLF & _ " Array $methodNames," & @CRLF & _ " $file," & @CRLF & _ " $startLine," & @CRLF & _ " $endLine" & @CRLF & _ " ) {" & @CRLF & _ " if ($className == '-') { // we are analyzing a function not a method" & @CRLF & _ " if (substr($methodName, 0, strlen('dummyFunctionForFile_')) == 'dummyFunctionForFile_') {" & @CRLF & _ " // the function has been introduced manually to encapsulate code in the global scope" & @CRLF & _ " $callerName = str_replace('_', '.', substr($methodName, strlen('dummyFunctionForFile_'))) . '(File)';" & @CRLF & _ " } else {" & @CRLF & _ " $callerName = $methodName . $this->generateParametersForSignature($this->codeSummary['functions'][$methodName]['params']);" & @CRLF & _ " }" & @CRLF & _ " } else {" & @CRLF & _ " //TODO: visibilities" & @CRLF & _ " $callerName = $className . '::' . $methodName . $this->generateParametersForSignature($this->codeSummary['classes'][$className]['methods'][$methodName]['params']);" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " $callerNameWithoutParameterList = substr($callerName, 0, strpos($callerName, '('));" & @CRLF & _ " " & @CRLF & _ " if (!in_array($callerNameWithoutParameterList, $this->ignoreList)) {" & @CRLF & _ " $this->debug('phpCallGraph: analyzing ' . $callerName);" & @CRLF & _ " $offset = $startLine - 1;" & @CRLF & _ " $length = $endLine - $startLine + 1;" & @CRLF & _ "" & @CRLF & _ " // obtain source code" & @CRLF & _ " $memberCode = implode('', array_slice(file($file), $offset, $length));" & @CRLF & _ " $memberCode = "<?php\nclass $className {\n" . $memberCode . "}\n?>\n";" & @CRLF & _ " //echo $memberCode;" & @CRLF & _ "" & @CRLF & _ " $this->debug("= Analyzing $callerName =");" & @CRLF & _ " $this->info(" defined in $file on line $offset");" & @CRLF & _ " $this->driver->startFunction($offset, $file, $callerName, $memberCode);" & @CRLF & _ "" & @CRLF & _ " $insideDoubleQuotedString = false;" & @CRLF & _ " $lineNumber = $offset - 1;" & @CRLF & _ " $blocksStarted = 0;" & @CRLF & _ " // parse source code" & @CRLF & _ " $tokens = token_get_all($memberCode);" & @CRLF & _ " /*" & @CRLF & _ " if ($methodName == '__construct') {" & @CRLF & _ " print_r($tokens);" & @CRLF & _ " }" & @CRLF & _ " //*/" & @CRLF & _ "" & @CRLF & _ " //TODO: implement a higher level API for working with PHP parser tokens (e.g. TokenIterator)" & @CRLF & _ " foreach ($tokens as $i => $token) {" & @CRLF & _ " //TODO: obtain method signature directly from the source file" & @CRLF & _ " if (is_array($token)) {" & @CRLF & _ " $lineNumber+= substr_count($token[1], "\n");" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " /*" & @CRLF & _ " if (count($token) == 3) {" & @CRLF & _ " echo "\t", token_name($token[0]), "\n";" & @CRLF & _ " echo "\t\t", $token[1], "\n";" & @CRLF & _ " } else {" & @CRLF & _ " echo "\t", $token[0], "\n";" & @CRLF & _ " }" & @CRLF & _ " //*/" & @CRLF & _ "" & @CRLF & _ " // skip call analysis for the method signature" & @CRLF & _ " if ($blocksStarted < 2) {" & @CRLF & _ " // method body not yet started" & @CRLF & _ " if ($token[0] == '{') {" & @CRLF & _ " ++$blocksStarted;" & @CRLF & _ " }" & @CRLF & _ " continue;" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " if (!$insideDoubleQuotedString and $token == '"') {" & @CRLF & _ " $insideDoubleQuotedString = true;" & @CRLF & _ " } elseif ($insideDoubleQuotedString and $token == '"') {" & @CRLF & _ " $insideDoubleQuotedString = false;" & @CRLF & _ " } elseif (!$insideDoubleQuotedString and $token != '"') {" & @CRLF & _ " if ($token[0] == T_STRING" & @CRLF & _ " //and ($token[1] != $className or $tokens[$i - 2][0] == T_NEW )" & @CRLF & _ " //and $token[1] != $methodName" & @CRLF & _ " ) {" & @CRLF & _ " if (" & @CRLF & _ " !in_array($token[1], $propertyNames) //TODO: property name equals name of a function or method" & @CRLF & _ " and !in_array($token[1], $this->constants) //TODO: constant name equals name of a function or method" & @CRLF & _ " and $token[1] != 'true'" & @CRLF & _ " and $token[1] != 'false'" & @CRLF & _ " and $token[1] != 'null'" & @CRLF & _ " ) {" & @CRLF & _ " $previousPreviousPreviousToken = $tokens[ $i - 3 ];" & @CRLF & _ " $previousPreviousToken = $tokens[ $i - 2 ];" & @CRLF & _ " $previousToken = $tokens[ $i - 1 ];" & @CRLF & _ " $nextToken = $tokens[ $i + 1 ];" & @CRLF & _ " $tokenAfterNext = $tokens[ $i + 2 ];" & @CRLF & _ "" & @CRLF & _ " $this->info($this->getTokenValues($tokens, $i));" & @CRLF & _ "" & @CRLF & _ "" & @CRLF & _ " if ($nextToken[0] == T_DOUBLE_COLON) {" & @CRLF & _ " // beginning of a call to a static method" & @CRLF & _ " //nop" & @CRLF & _ " continue;" & @CRLF & _ " } elseif (" & @CRLF & _ " (" & @CRLF & _ " $tokens[ $i - 4][0] == T_CATCH" & @CRLF & _ " and $previousPreviousPreviousToken[0] == T_WHITESPACE" & @CRLF & _ " and $previousPreviousToken == '('" & @CRLF & _ " and $previousToken[0] == T_WHITESPACE" & @CRLF & _ " )" & @CRLF & _ " or" & @CRLF & _ " (" & @CRLF & _ " $previousPreviousPreviousToken[0] == T_CATCH" & @CRLF & _ " and $previousPreviousToken[0] == T_WHITESPACE" & @CRLF & _ " and $previousToken == '('" & @CRLF & _ " )" & @CRLF & _ " or" & @CRLF & _ " (" & @CRLF & _ " $previousPreviousToken[0] == T_CATCH" & @CRLF & _ " and $previousToken == '('" & @CRLF & _ " )" & @CRLF & _ " ){" & @CRLF & _ " // catch block" & @CRLF & _ " continue;" & @CRLF & _ " } elseif ($previousPreviousToken[0] == T_NEW){" & @CRLF & _ " $this->debug('Found object creation with new operator');" & @CRLF & _ " if (!$this->showExternalCalls) {" & @CRLF & _ " continue;" & @CRLF & _ " }" & @CRLF & _ " $calleeClass = $token[1];" & @CRLF & _ " if (isset($this->codeSummary['classes'][$calleeClass])) {" & @CRLF & _ " // find constructor method" & @CRLF & _ " if (isset($this->codeSummary['classes'][$calleeClass]['methods']['__construct'])) {" & @CRLF & _ " $calleeName = "$calleeClass::__construct"" & @CRLF & _ " . $this->generateParametersForSignature($this->codeSummary['classes'][$calleeClass]['methods']['__construct']['params']);" & @CRLF & _ " } elseif (isset($this->codeSummary['classes'][$calleeClass]['methods'][$calleeClass])) {" & @CRLF & _ " $calleeName = "$calleeClass::$calleeClass"" & @CRLF & _ " . $this->generateParametersForSignature($this->codeSummary['classes'][$calleeClass]['methods'][$calleeClass]['params']);" & @CRLF & _ " } else {" & @CRLF & _ " $calleeName = "$calleeClass::__construct()";" & @CRLF & _ " }" & @CRLF & _ " $calleeFile = $this->codeSummary['classes'][$calleeClass]['file'];" & @CRLF & _ " } else {" & @CRLF & _ " // TODO: decide how this case should be handled (could be a PEAR class or a class of a PHP extension, e.g. GTK)" & @CRLF & _ " //if ($this->showInternalFunctions)" & @CRLF & _ " $calleeName = "$calleeClass::__construct()"; // TODO: it could also be $calleeClass::$calleeClass() implemented in PHP4-style, however if we don't have the code, we can't now" & @CRLF & _ " $calleeFile = '';" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " $this->info($this->getTokenValues($tokens, $i));" & @CRLF & _ " $this->recordVariableAsType($calleeClass, $tokens[$i-6][1]);" & @CRLF & _ " } elseif (" & @CRLF & _ " (" & @CRLF & _ " isset($previousPreviousToken[1]) and $previousPreviousToken[1] == '$this'" & @CRLF & _ " and $previousToken[0] == T_OBJECT_OPERATOR" & @CRLF & _ " and in_array($token[1], $methodNames)" & @CRLF & _ " )" & @CRLF & _ " or" & @CRLF & _ " (" & @CRLF & _ " isset($previousPreviousToken[1]) and $previousPreviousToken[1] == 'self'" & @CRLF & _ " and $previousToken[0] == T_DOUBLE_COLON" & @CRLF & _ " and in_array($token[1], $methodNames)" & @CRLF & _ " )" & @CRLF & _ " ){" & @CRLF & _ " $this->info('internal method call ($this-> and self:: and $className::)');" & @CRLF & _ " $calleeName = "$className::{$token[1]}" . $this->generateParametersForSignature($this->codeSummary['classes'][$className]['methods'][$token[1]]['params']);" & @CRLF & _ " $calleeFile = $file;" & @CRLF & _ " } elseif ($previousToken[0] == T_OBJECT_OPERATOR) {" & @CRLF & _ " $this->debug('External method call or property access'); " & @CRLF & _ " //TODO: what if a object holds another instance of its class" & @CRLF & _ " if (!$this->showExternalCalls) {" & @CRLF & _ " continue;" & @CRLF & _ " }" & @CRLF & _ " if ($nextToken == '(' or ($nextToken[0] == T_WHITESPACE and $tokenAfterNext == '(')) {" & @CRLF & _ " $calleeName = $token[1];" & @CRLF & _ " $this->debug("Calling for $calleeName");" & @CRLF & _ "" & @CRLF & _ " $variable = $tokens[$i-2][1];" & @CRLF & _ " $this->debug("Variable = $variable");" & @CRLF & _ " $calleeClass = $this->lookupTypeForVariable($variable);" & @CRLF & _ " $this->debug('found as ' . $calleeClass);" & @CRLF & _ " if ($calleeClass) {" & @CRLF & _ " $calleeParams = $this->generateParametersForSignature(" & @CRLF & _ " $this->codeSummary['classes'][$calleeClass]['methods'][$calleeName]['params']" & @CRLF & _ " );" & @CRLF & _ " $calleeFile = $this->codeSummary['classes'][$calleeClass]['file'];" & @CRLF & _ " } else {" & @CRLF & _ " if (" & @CRLF & _ " isset($this->methodLookupTable[$calleeName])" & @CRLF & _ " and count($this->methodLookupTable[$calleeName]) == 1" & @CRLF & _ " ) {" & @CRLF & _ " // there is only one class having a method with this name" & @CRLF & _ " // SMELL: but if the user only registers part of a system the only one hit " & @CRLF & _ " // is not necessarily valid." & @CRLF & _ " $calleeClass = $this->methodLookupTable[$calleeName][0];" & @CRLF & _ " if (isset($this->codeSummary['classes'][$calleeClass])) {" & @CRLF & _ " $calleeParams = $this->generateParametersForSignature(" & @CRLF & _ " $this->codeSummary['classes'][$calleeClass]['methods'][$calleeName]['params']" & @CRLF & _ " );" & @CRLF & _ " $calleeFile = $this->codeSummary['classes'][$calleeClass]['file'];" & @CRLF & _ "" & @CRLF & _ " $this->info("RECORDING CLASS OF $previousPreviousToken[1] VARIABLE to be $calleeClass\n");" & @CRLF & _ " $this->info($this->getTokenValues($tokens, $i));" & @CRLF & _ "" & @CRLF & _ " } else {" & @CRLF & _ " $this-warning("calleeClass is unset");" & @CRLF & _ " $calleeParams = null;" & @CRLF & _ " $calleeFile = null;" & @CRLF & _ " }" & @CRLF & _ " } else {" & @CRLF & _ " $numEntries = count($this->methodLookupTable[$calleeName]);" & @CRLF & _ " if ($numEntries == 0) {" & @CRLF & _ " $this->warning("method $calleeName was called, but I have no record for that");" & @CRLF & _ " } else {" & @CRLF & _ " $this->warning("I have $numEntries for $calleeName!");" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " $this->info($this->getTokenValues($tokens, $i));" & @CRLF & _ "" & @CRLF & _ " $calleeClass = '';" & @CRLF & _ " $calleeParams = '()';" & @CRLF & _ " $calleeFile = '';" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ " $calleeName = "$calleeClass::$calleeName$calleeParams";" & @CRLF & _ " } else {" & @CRLF & _ " $this->info("Property access");" & @CRLF & _ " continue;" & @CRLF & _ " }" & @CRLF & _ " } elseif ($previousToken[0] == T_DOUBLE_COLON){" & @CRLF & _ " $this->debug("static external method call");" & @CRLF & _ " if (!$this->showExternalCalls) {" & @CRLF & _ " continue;" & @CRLF & _ " }" & @CRLF & _ " if ($nextToken != '(' and !($nextToken[0] == T_WHITESPACE and $tokenAfterNext == '(')) {" & @CRLF & _ " // constant access" & @CRLF & _ " continue;" & @CRLF & _ " }" & @CRLF & _ " $calleeClass = $previousPreviousToken[1];" & @CRLF & _ " $calleeMethod = $token[1];" & @CRLF & _ " $calleeFile = '';" & @CRLF & _ " $calleeParams = '()';" & @CRLF & _ " // parent::" & @CRLF & _ " if ($calleeClass == 'parent' and !empty($this->codeSummary['classes'][$className]['parentClass'])) {" & @CRLF & _ " $calleeClass = $this->codeSummary['classes'][$className]['parentClass'];" & @CRLF & _ " }" & @CRLF & _ " if (isset($this->codeSummary['classes'][$calleeClass])) {" & @CRLF & _ " $calleeFile = $this->codeSummary['classes'][$calleeClass]['file'];" & @CRLF & _ " if (isset($this->codeSummary['classes'][$calleeClass]['methods'][$calleeMethod]['params'])) {" & @CRLF & _ " $calleeParams = $this->generateParametersForSignature($this->codeSummary['classes'][$calleeClass]['methods'][$calleeMethod]['params']);" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ " $calleeName = "$calleeClass::$calleeMethod$calleeParams";" & @CRLF & _ " //TODO: handle self::myMethod(); $className::myMethod(); here => abolish internal method call case" & @CRLF & _ " } else {" & @CRLF & _ "" & @CRLF & _ " $calledFunction = $token[1];" & @CRLF & _ " $calleeFile = '';" & @CRLF & _ " $calleeParams = '()';" & @CRLF & _ " " & @CRLF & _ " $this->info("Function call: ".$calledFunction);" & @CRLF & _ "" & @CRLF & _ " if (in_array($calledFunction, $this->internalFunctions)) {" & @CRLF & _ " if (!$this->showInternalFunctions) {" & @CRLF & _ " continue;" & @CRLF & _ " }" & @CRLF & _ " } else {" & @CRLF & _ " if (!$this->showExternalCalls) {" & @CRLF & _ " continue;" & @CRLF & _ " }" & @CRLF & _ " if (isset($this->codeSummary['functions'][$calledFunction])) {" & @CRLF & _ " $calleeFile = $this->codeSummary['functions'][$calledFunction]['file'];" & @CRLF & _ " if (isset($this->codeSummary['functions'][$calledFunction]['params'])) {" & @CRLF & _ " $calleeParams = $this->generateParametersForSignature($this->codeSummary['functions'][$calledFunction]['params']);" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ " $calleeName = $calledFunction . $calleeParams;" & @CRLF & _ " }" & @CRLF & _ " $this->debug("---> $calleeName called from line $lineNumber and defined in $calleeFile");" & @CRLF & _ " $this->driver->addCall($lineNumber, $calleeFile, $calleeName);" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ " } else {" & @CRLF & _ " //TODO: parse calls inside double quoted strings" & @CRLF & _ " $this->info(' ignoring code inside ""');" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ " $this->debug('== endFunction ==');" & @CRLF & _ " $this->driver->endFunction();" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ "}" & @CRLF & _ "" & @CRLF & _ " public function generateParametersForSignature($parameters) {" & @CRLF & _ " $result = '(';" & @CRLF & _ " if (!empty($parameters)) {" & @CRLF & _ " foreach($parameters as $parameterName => $parameter) {" & @CRLF & _ " if ($parameter['byReference']) {" & @CRLF & _ " $result.= '&';" & @CRLF & _ " }" & @CRLF & _ " $result.= '$' . $parameterName . ', ';" & @CRLF & _ " }" & @CRLF & _ " $result = substr($result, 0, -2);" & @CRLF & _ " }" & @CRLF & _ " $result.= ')';" & @CRLF & _ " return $result;" & @CRLF & _ " }" & @CRLF & _ "}" & @CRLF & _ " public function __toString() {" & @CRLF & _ " return $this->driver->__toString();" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " public function save($file) {" & @CRLF & _ " return file_put_contents($file, $this->__toString());" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " " & @CRLF & _ " protected function getTokenValues($tokens, $i) {" & @CRLF & _ " $width = 10;" & @CRLF & _ " $pad = ' ';" & @CRLF & _ " $out = "\n";" & @CRLF & _ " $start = -5;" & @CRLF & _ " $end = 4;" & @CRLF & _ " $headerLine = '';" & @CRLF & _ " $rowLine = '';" & @CRLF & _ " $tokenLine = '';" & @CRLF & _ " for ($j = $start; $j <= $end; $j++) {" & @CRLF & _ " $n = ($i + $j);" & @CRLF & _ " $currentToken = $tokens[$n];" & @CRLF & _ " $tokenType = '';" & @CRLF & _ " $cell = '';" & @CRLF & _ " $header = '';" & @CRLF & _ " if (is_array($currentToken)) {" & @CRLF & _ " $mainValue = $currentToken[1];" & @CRLF & _ " $mainValue = str_replace("\n", '\n', $mainValue);" & @CRLF & _ " $mainValue = str_replace("\t", '\t', $mainValue);" & @CRLF & _ " if ($mainVlaue = '') {" & @CRLF & _ " $mainValue = 'nil';" & @CRLF & _ " } " & @CRLF & _ " $cell = $mainValue;" & @CRLF & _ " $tokenType = token_name($currentToken[0]);" & @CRLF & _ " } else {" & @CRLF & _ " $cell = '"'.$currentToken.'"';" & @CRLF & _ " }" & @CRLF & _ " $cell = $cell;" & @CRLF & _ " $cell = str_pad($cell, $width, $pad);" & @CRLF & _ " $tokenType = str_pad(substr($tokenType,0,$width), $width, $pad);" & @CRLF & _ " $header = '['.$j.']';" & @CRLF & _ " $header = str_pad($header, $width, $pad);" & @CRLF & _ "" & @CRLF & _ " $headerLine .= $header.' ';" & @CRLF & _ " $rowLine .= $cell.' ';" & @CRLF & _ " $tokenLine .= $tokenType.' ';" & @CRLF & _ " }" & @CRLF & _ " $out .= $headerLine."\n";" & @CRLF & _ " $out .= $rowLine."\n";" & @CRLF & _ " $out .= $tokenLine."\n";" & @CRLF & _ " return $out;" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " protected $variableTypes = array();" & @CRLF & _ " protected function recordVariableAsType($class, $variable) {" & @CRLF & _ " $this->debug("RECORDING $variable AS TYPE $class");" & @CRLF & _ " $this->variableTypes[$variable] = $class;" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ "" & @CRLF & _ " /**" & @CRLF & _ " * Returns a recorded type for a given variable, unless the variable is named '$self'" & @CRLF & _ " * in which case returns the class name." & @CRLF & _ " * If no match is found returns null." & @CRLF & _ " */" & @CRLF & _ " protected function lookupTypeForVariable($variable) {" & @CRLF & _ " $recordedType = $this->variableTypes[$variable];" & @CRLF & _ " if ($recordedType) {" & @CRLF & _ " $type = $recordedType;" & @CRLF & _ " } else {" & @CRLF & _ " $this->warning("No recorded type for $variable");" & @CRLF & _ " $type = null;" & @CRLF & _ " }" & @CRLF & _ " $this->info('LOOKUP FOR '.$variable.' returns '.$type);" & @CRLF & _ " return $type;" & @CRLF & _ " }" & @CRLF & _ "}" & @CRLF & _ "?>" & @CRLF & _ "<?php" & @CRLF & _ "/**" & @CRLF & _ " * Implementation of a call graph generation strategy wich renders a graph with" & @CRLF & _ " * dot." & @CRLF & _ " *" & @CRLF & _ " * PHP version 5" & @CRLF & _ " *" & @CRLF & _ " * This file is part of phpCallGraph." & @CRLF & _ " *" & @CRLF & _ " * PHPCallGraph is free software; you can redistribute it and/or modify" & @CRLF & _ " * it under the terms of the GNU General Public License as published by" & @CRLF & _ " * the Free Software Foundation; either version 3 of the License, or" & @CRLF & _ " * (at your option) any later version." & @CRLF & _ " *" & @CRLF & _ " * PHPCallGraph is distributed in the hope that it will be useful," & @CRLF & _ " * but WITHOUT ANY WARRANTY; without even the implied warranty of" & @CRLF & _ " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the" & @CRLF & _ " * GNU General Public License for more details." & @CRLF & _ " *" & @CRLF & _ " * You should have received a copy of the GNU General Public License" & @CRLF & _ " * along with this program. If not, see <http://www.gnu.org/licenses/>." & @CRLF & _ " *" & @CRLF & _ " * @package PHPCallGraph" & @CRLF & _ " * @author Falko Menge <fakko at users dot sourceforge dot net>" & @CRLF & _ " * @copyright 2007-2009 Falko Menge" & @CRLF & _ " * @license http://www.gnu.org/licenses/gpl.txt GNU General Public License" & @CRLF & _ " */" & @CRLF & _ "" & @CRLF & _ "// reduce warnings because of PEAR dependency" & @CRLF & _ "error_reporting(E_ALL ^ E_NOTICE);" & @CRLF & _ "" & @CRLF & _ "require_once 'CallgraphDriver.php';" & @CRLF & _ "require_once 'Image/GraphViz.php';" & @CRLF & _ "" & @CRLF & _ "/**" & @CRLF & _ " * Implementation of a call graph generation strategy wich renders a graph with" & @CRLF & _ " * dot." & @CRLF & _ " */" & @CRLF & _ "class GraphVizDriver implements CallgraphDriver {" & @CRLF & _ "" & @CRLF & _ " protected $outputFormat;" & @CRLF & _ " protected $dotCommand;" & @CRLF & _ " protected $useColor = true;" & @CRLF & _ " protected $graph;" & @CRLF & _ " protected $currentCaller = '';" & @CRLF & _ " protected $internalFunctions;" & @CRLF & _ "}" & @CRLF & _ " /**" & @CRLF & _ " * @return CallgraphDriver" & @CRLF & _ " */" & @CRLF & _ " public function __construct($outputFormat = 'png', $dotCommand = 'dot') {" & @CRLF & _ " $this->initializeNewGraph();" & @CRLF & _ " $this->setDotCommand($dotCommand);" & @CRLF & _ " $this->setOutputFormat($outputFormat);" & @CRLF & _ " $functions = get_defined_functions();" & @CRLF & _ " $this->internalFunctions = $functions['internal'];" & @CRLF & _ " " & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " /**" & @CRLF & _ " * @return void" & @CRLF & _ " */" & @CRLF & _ " public function reset() {" & @CRLF & _ " $this->initializeNewGraph();" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " /**" & @CRLF & _ " * @return void" & @CRLF & _ " */" & @CRLF & _ " protected function initializeNewGraph() {" & @CRLF & _ " $this->graph = new Image_GraphViz(" & @CRLF & _ " true," & @CRLF & _ " array(" & @CRLF & _ " 'fontname' => 'Verdana'," & @CRLF & _ " 'fontsize' => 12.0," & @CRLF & _ " //'fontcolor' => 'gray5'," & @CRLF & _ " 'rankdir' => 'LR', // left-to-right" & @CRLF & _ " )" & @CRLF & _ " );" & @CRLF & _ " $this->graph->dotCommand = $this->dotCommand;" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " /**" & @CRLF & _ " * Sets path to GraphViz/dot command" & @CRLF & _ " * @param string $dotCommand Path to GraphViz/dot command" & @CRLF & _ " * @return void" & @CRLF & _ " */" & @CRLF & _ " public function setDotCommand($dotCommand = 'dot') {" & @CRLF & _ " $this->dotCommand = $dotCommand;" & @CRLF & _ " $this->graph->dotCommand = $dotCommand;" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " /**" & @CRLF & _ " * Sets output format" & @CRLF & _ " * @param string $outputFormat One of the output formats supported by GraphViz/dot" & @CRLF & _ " * @return void" & @CRLF & _ " */" & @CRLF & _ " public function setOutputFormat($outputFormat = 'png') {" & @CRLF & _ " $this->outputFormat = $outputFormat;" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " /**" & @CRLF & _ " * Enables or disables the use of color" & @CRLF & _ " * @param boolean $boolean True if color should be used" & @CRLF & _ " * @return void" & @CRLF & _ " */" & @CRLF & _ " public function setUseColor($boolean = true) {" & @CRLF & _ " $this->useColor = $boolean;" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " /**" & @CRLF & _ " * @param integer $line" & @CRLF & _ " * @param string $file" & @CRLF & _ " * @param string $name" & @CRLF & _ " * @return void" & @CRLF & _ " */" & @CRLF & _ " public function startFunction($line, $file, $name, $memberCode) {" & @CRLF & _ " $this->addNode($name);" & @CRLF & _ " $this->currentCaller = $name;" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " /**" & @CRLF & _ " * @param integer $line" & @CRLF & _ " * @param string $file" & @CRLF & _ " * @param string $name" & @CRLF & _ " * @return void" & @CRLF & _ " */" & @CRLF & _ " public function addCall($line, $file, $name) {" & @CRLF & _ " $this->addNode($name);" & @CRLF & _ " $this->graph->addEdge(array($this->currentCaller => $name));" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " /**" & @CRLF & _ " * @return void" & @CRLF & _ " */" & @CRLF & _ " protected function addNode($name) {" & @CRLF & _ " $nameParts = explode('::', $name);" & @CRLF & _ " $cluster = 'default';" & @CRLF & _ " $label = $name;" & @CRLF & _ " $color = 'lavender'; //lightblue2, lightsteelblue2, azure2, slategray2" & @CRLF & _ " if (count($nameParts) == 2) { // method call" & @CRLF & _ " if (empty($nameParts[0])) {" & @CRLF & _ " $cluster = 'class is unknown';" & @CRLF & _ " } else {" & @CRLF & _ " $cluster = $nameParts[0];" & @CRLF & _ " }" & @CRLF & _ " // obtain method name" & @CRLF & _ " $label = $nameParts[1];" & @CRLF & _ " }" & @CRLF & _ " // remove parameter list" & @CRLF & _ " $label = substr($label, 0, strpos($label, '('));" & @CRLF & _ "" & @CRLF & _ " if (count($nameParts) == 1) { // function call" & @CRLF & _ " if (in_array($label, $this->internalFunctions)) { // call to internal function" & @CRLF & _ " $cluster = 'internal PHP functions';" & @CRLF & _ " }" & @CRLF & _ " }" & @CRLF & _ " $this->graph->addNode(" & @CRLF & _ " $name," & @CRLF & _ " array(" & @CRLF & _ " 'fontname' => 'Verdana'," & @CRLF & _ " 'fontsize' => 12.0," & @CRLF & _ " //'fontcolor' => 'gray5'," & @CRLF & _ " 'label' => $label," & @CRLF & _ " //'style' => 'rounded' . ($this->useColor ? ',filled' : ''), // produces errors in rendering" & @CRLF & _ " 'style' => ($this->useColor ? 'filled' : 'rounded')," & @CRLF & _ " 'color' => ($this->useColor ? $color : 'black')," & @CRLF & _ " 'shape' => ($this->useColor ? 'ellipse' : 'rectangle')," & @CRLF & _ " )," & @CRLF & _ " $cluster" & @CRLF & _ " );" & @CRLF & _ " //*" & @CRLF & _ " $this->graph->addCluster(" & @CRLF & _ " $cluster," & @CRLF & _ " $cluster," & @CRLF & _ " array(" & @CRLF & _ "// 'style' => ($this->useColor ? 'filled' : '')," & @CRLF & _ " 'color' => 'gray20'," & @CRLF & _ "// 'bgcolor' => ''," & @CRLF & _ " )" & @CRLF & _ " );" & @CRLF & _ " //*/" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " /**" & @CRLF & _ " * @return void" & @CRLF & _ " */" & @CRLF & _ " public function endFunction() {" & @CRLF & _ " }" & @CRLF & _ "" & @CRLF & _ " /**" & @CRLF & _ " * @return string" & @CRLF & _ " */" & @CRLF & _ " public function __toString() {" & @CRLF & _ " return $this->graph->fetch($this->outputFormat);" & @CRLF & _ " }" & @CRLF & _ "}" & @CRLF & _ "?>" & @CRLF & _ "" Local $aArray = StringRegExp($sString, $sRegex, $STR_REGEXPARRAYGLOBALFULLMATCH) Local $aFullArray[0] For $i = 0 To UBound($aArray) -1 _ArrayConcatenate($aFullArray, $aArray[$i]) Next $aArray = $aFullArray ; Present the entire match result _ArrayDisplay($aArray, "Result")

Please keep in mind that these code samples are automatically generated and are not guaranteed to work. If you find any syntax errors, feel free to submit a bug report. For a full regex reference for AutoIt, please visit: https://www.autoitscript.com/autoit3/docs/functions/StringRegExp.htm