protected function _replaceTokens($input, $source, $tokenStart, $tokenEnd, $default = null)
    {
        $input   = $this->_normalizeString($input);
        $default = $default === null ? '' : $this->_normalizeString($default);

        $regexDelimiter = '/';
        $tokenStart     = $this->_quoteRegex($tokenStart, $regexDelimiter);
        $tokenEnd       = $this->_quoteRegex($tokenEnd, $regexDelimiter);

        $regex   = $regexDelimiter . $tokenStart . '(.*?)' . $tokenEnd . $regexDelimiter;
        $matches = $this->_getAllMatchesRegex($regex, $input);

        foreach ($matches[0] as $i => $token) {
            $key = $matches[1][$i];
            $key = $this->_normalizeTokenKey($key);

            try {
                $value = $this->_containerGet($source, $key);
            } catch (NotFoundExceptionInterface $e) {
                $value = $default;
            } catch (RootException $e) {
                $this->_createRuntimeException($this->__('Could not access reference value for key "%1$s"', [$key]), null, $e);
            }

            try {
                $input = $this->_stringableReplace($token, $value, $input);
            } catch (RootException $e) {
                $this->_createRuntimeException($this->__('Could not replace token with key "%1$s"', [$key]), null, $e);
            }
        }

        return $input;
    }