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
  • Non-capturing group
    (?:...)
  • Capturing group
    (...)
  • 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

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

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 JavaScript, please visit: https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions