Get a string suitable as a preg_replace() replacement for given PHP code

@param  string     $php Original code
@return array|bool      Array of [regexp, replacement] if possible, or FALSE otherwise
199913
protected static function getDynamicRendering($php)
	{
		$rendering = '';

		$literal   = "(?<literal>'((?>[^'\\\\]+|\\\\['\\\\])*)')";
		$attribute = "(?<attribute>htmlspecialchars\\(\\\$node->getAttribute\\('([^']+)'\\),2\\))";
		$value     = "(?<value>$literal|$attribute)";
		$output    = "(?<output>\\\$this->out\\.=$value(?:\\.(?&value))*;)";

		$copyOfAttribute = "(?<copyOfAttribute>if\\(\\\$node->hasAttribute\\('([^']+)'\\)\\)\\{\\\$this->out\\.=' \\g-1=\"'\\.htmlspecialchars\\(\\\$node->getAttribute\\('\\g-1'\\),2\\)\\.'\"';\\})";

		$regexp = '(^(' . $output . '|' . $copyOfAttribute . ')*$)';
		if (!preg_match($regexp, $php, $m))
		{
			return false;
		}

		// Attributes that are copied in the replacement
		$copiedAttributes = [];

		// Attributes whose value is used in the replacement
		$usedAttributes = [];

		$regexp = '(' . $output . '|' . $copyOfAttribute . ')A';
		$offset = 0;
		while (preg_match($regexp, $php, $m, 0, $offset))
		{
			// Test whether it's normal output or a copy of attribute
			if ($m['output'])
			{
				// 12 === strlen('$this->out.=')
				$offset += 12;

				while (preg_match('(' . $value . ')A', $php, $m, 0, $offset))
				{
					// Test whether it's a literal or an attribute value
					if ($m['literal'])
					{
						// Unescape the literal
						$str = stripslashes(substr($m[0], 1, -1));

						// Escape special characters
						$rendering .= preg_replace('([\\\\$](?=\\d))', '\\\\$0', $str);
					}
					else
					{
						$attrName = end($m);

						// Generate a unique ID for this attribute name, we'll use it as a
						// placeholder until we have the full list of captures and we can replace it
						// with the capture number
						if (!isset($usedAttributes[$attrName]))
						{
							$usedAttributes[$attrName] = uniqid($attrName, true);
						}

						$rendering .= $usedAttributes[$attrName];
					}

					// Skip the match plus the next . or ;
					$offset += 1 + strlen($m[0]);
				}
			}
			else
			{
				$attrName = end($m);

				if (!isset($copiedAttributes[$attrName]))
				{
					$copiedAttributes[$attrName] = uniqid($attrName, true);
				}

				$rendering .= $copiedAttributes[$attrName];
				$offset += strlen($m[0]);
			}
		}

		// Gather the names of the attributes used in the replacement either by copy or by value
		$attrNames = array_keys($copiedAttributes + $usedAttributes);

		// Sort them alphabetically
		sort($attrNames);

		// Keep a copy of the attribute names to be used in the fillter subpattern
		$remainingAttributes = array_combine($attrNames, $attrNames);

		// Prepare the final regexp
		$regexp = '(^[^ ]+';
		$index  = 0;
		foreach ($attrNames as $attrName)
		{
			// Add a subpattern that matches (and skips) any attribute definition that is not one of
			// the remaining attributes we're trying to match
			$regexp .= '(?> (?!' . RegexpBuilder::fromList($remainingAttributes) . '=)[^=]+="[^"]*")*';
			unset($remainingAttributes[$attrName]);

			$regexp .= '(';

			if (isset($copiedAttributes[$attrName]))
			{
				self::replacePlaceholder($rendering, $copiedAttributes[$attrName], ++$index);
			}
			else
			{
				$regexp .= '?>';
			}

			$regexp .= ' ' . $attrName . '="';

			if (isset($usedAttributes[$attrName]))
			{
				$regexp .= '(';

				self::replacePlaceholder($rendering, $usedAttributes[$attrName], ++$index);
			}

			$regexp .= '[^"]*';

			if (isset($usedAttributes[$attrName]))
			{
				$regexp .= ')';
			}

			$regexp .= '")?';
		}

		$regexp .= '.*)s';

		return [$regexp, $rendering];
	}
567228
public function replaceLinks($string)
    {
        preg_match_all('/(\[content_url\](.*?)\[\/content_url\]|\[content_url\](.*?)\[\\\\\/content_url\])/', $string, $matches);

        if (!count($matches)) {
            return $string;
        }

        if (!empty($matches[3][0])) {
            $matches[1] = $matches[3];
        } elseif (!empty($matches[2][0])) {
            $matches[1] = $matches[2];
        }

        /** @var ContentInterface[] $contents */
        $contents = $this->contentManager->getRepository()->findByIds($matches[1]);
        $array = [];
        foreach ($contents as $content) {
            $array[$content->getId()] = $content;
        }

        foreach ($matches[0] as $key => $match) {
            if (isset($array[$matches[1][$key]])) {
                $content = $array[$matches[1][$key]];

                $url = $this->router->generate('_content', ['slug' => $content->getSlug()]);
            } else {
                $url = $this->router->generate('_content', ['slug' => '404']);
            }

            $string = str_replace($match, $url, $string);
        }

        return $string;
    }
838611
public function resolveLinksInString($string)
    {
        return preg_replace_callback(
            '/(?<!\\\){@(.*?)}/',
            function ($matches) {
                try {
                    return $this->offsetGet($matches[1]);
                } catch (\OutOfBoundsException $e) {
                    return $matches[0];
                }
            },
            $string
        );
    }
601657
public static function replaceStringsAndComments($text)
    {
        if (is_string($text)) {
            // Fast pre-check, to optimize performance
            if (strpos($text, "'") !== false || strpos($text, '"') !== false) {
                // Replace all strings in quotes (also in comments, but that's okay - removed in next step)
                $replaceStringCallback = function ($matches) {
                    return self::addStringReplacement($matches[1] . $matches[2] . $matches[1]);
                };
                $text = preg_replace('/\r/', '', $text);
                $text = preg_replace('/\\\\\n/', '_STRING_CSSLINEBREAK_', $text);
                $text = preg_replace('/\\\\"/', '_STRING_ESCAPEDDOUBLEQUOTE_', $text);
                $text = preg_replace('/\\\\\'/', '_STRING_ESCAPEDSINGLEQUOTE_', $text);
                $text = preg_replace_callback('/("|\')(.*?)\g{1}/', $replaceStringCallback, $text);
            }

            if (strpos($text, "data:") !== false) {
                // Replace all data URIs
                // (that are not in quotes and therefor were not replaced by the previous check)
                $replaceDataUriCallback = function ($matches) {
                    return self::addStringReplacement($matches[1]);
                };
                $text = preg_replace_callback(
                    '/(data:(?:[^;,]+)?(?:;charset=[^;,]+)?' .
                    '(?:;base64,(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?|,[-.a-zA-Z0-9_%]+))/',
                    $replaceDataUriCallback,
                    $text
                );
            }

            // Fast pre-check, to optimize performance
            if (strpos($text, "*") !== false) {
                // Strip multi-line comments (after string replace to keep comments in strings)
                $replaceCommentCallback = function ($matches) {
                    return self::addCommentReplacement($matches[1]);
                };
                $text = preg_replace_callback('/(\/\*.*?\*\/)/', $replaceCommentCallback, $text);
            }

            return $text;
        } else {
            throw new \InvalidArgumentException(
                "Invalid type '" . gettype($text). "' for argument 'text' given."
            );
        }
    }
825054
public static function get($string)
    {
        $vars = func_get_args();

        if (array_key_exists($string, self::$strings)) {
            $vars[0] = self::$strings[$string];
            return call_user_func_array('sprintf', $vars);
        }

        return '%%MISSING STRING: ' . $string . '%%';
    }
137487
public static function replace($string, array $vars)
    {
        if (preg_match_all('/:([a-z_]+)/', $string, $matches)) {
            list($original, $variables) = $matches;

            foreach ($variables as $key => $var) {
                if (isset($vars[$var])) {
                    $string = str_replace($original[$key], $vars[$var], $string);
                }
            }
        }

        return $string;
    }
670090
public function replace($string)
    {
        foreach ($this->bag as $key => $value) {
            $string = str_replace($key, $value, $string);
        }

        return $string;
    }
660437
public static function replace($match, $replace, $org)
    {
        //if $match satisfies regular expression
        if (is::regex($match)) {
            return preg_replace($match, $replace, $org);
        } else {
            return str_replace($match, $replace, $org);
        }
    }
1188414
public function convertToString($html)
    {
        $externalJavaScript = $this->extractExternalJavaScript($html);

        return $this->replaceJavaScriptTags($html, $externalJavaScript);
    }
483933
public function htmlchars($php)
    {
        // PHP strings can be escaped at compile time
        if (preg_match('/^\'((?:[^\'{]+|\\\\.)*)\'$/s', $php, $m)) {
            return "'".htmlspecialchars(str_replace('\\\'', "'", $m[1]), ENT_QUOTES, $this->encoding)."'";
        }
        return 'phptal_escape('.$php.', \''.$this->encoding.'\')';
    }
534307
public function apply(string $string) : string
    {
        return preg_replace($this->pattern, $this->replacement, $string);
    }
935695
public function replaceTokens($string)
    {
        foreach ($this->getTokenNames($string) as $token) {
            $string = str_replace("{{$token}}", $this->getTokenValue($token), $string);
        }
        
        return $string;
    }
898365
public function stripVariables($string)
    {
        if (strpos($string, '$') === false) {
            return $string;
        }

        return preg_replace(self::REGEX_COMPLEX_VARS, '', $string);
    }
913329
protected function replaceWithVariables($string)
    {
        if (preg_match_all('/:([a-z_]+)/', $string, $matches)) {
            list(
                $original,
                $vars
            ) = $matches;

            foreach ($vars as $key => $var) {
                if (isset($this->vars[$var])) {
                    $string = str_replace($original[$key], $this->vars[$var], $string);
                }
            }
        }

        return $string;
    }
1183981
public function regEx($type)
    {
        switch ($type) {
            case 'php':
                $f = $this->phpFunction();
                $regex = '/->'.$f.'\(\s*\n*\r*(["\'])(?<text>(.|\n|\r|\n\r)*?)\s*\n*\r*\1\)/i';
                break;

            case 'mustache':
                $tag = $this->mustacheTag();
                $regex = '/({{|\[\[)\s*#\s*'.$tag.'\s*(}}|\]\])(?<text>(.|\n|\r|\n\r)*?)({{|\[\[)\s*\/\s*'.$tag.'\s*(}}|\]\])/i';
                break;

            default:
                $regex = '/({{|\[\[)\s*#\s*_t\s*(}}|\]\])(?<text>(.|\n|\r|\n\r)*?)({{|\[\[)\s*\/\s*_t\s*(}}|\]\])/i';
                break;
        }

        return $regex;
    }
1164094
protected function parseString($string) {
        $matches = [];

        if (preg_match_all($this->regex, $string, $result) !== false) {
            $matches = $result[0];
        }

        return $matches;
    }
1089580
public function replace($text)
    {
        preg_match_all($this->pattern, $text, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
        $delta = 0;
        foreach ($matches as $match)
        {
            $stringsOnly = array();
            foreach ($match as $info)
            {
                $stringsOnly []= $info[0];
            }
            $replace = call_user_func($this->callback, $stringsOnly);
            if (false === $replace || null === $replace)
            {
                continue;
            }

            $text = substr_replace($text, $replace, $match[0][1] + $delta, strlen($match[0][0]));
            $delta += strlen($replace) - strlen($match[0][0]);
        }

        return $text;
    }