Parses a tag for the tag attributes and inner content.
@access private
@param string $str The tag string to be parsed.
@param string $tagname The prefix of the custom tag being parsed.
@return array The tag
332963
private function _buildTag($str, $tagname)
        {
//          $tagname = $this->_options['tag_name'];
            $tag = array(
                'block'         => $str,
                'content'       => '',
                'name'          => '',
                'attributes'    => array()
            );
            $begin_len = strlen(self::$tag_open.$tagname.':');
//          echo substr($str, 0, $begin_len)."\r\n";
            if(substr($str, 0, $begin_len) !== self::$tag_open.$tagname.':')
            {
//              closing tag
                $tag['name'] = '___text';
                return $tag;
            }
            else if(substr($str, 1, 1) === '/')
            {
//              closing tag
                $tag['name'] = '---ERROR---';
                return $tag;
            }
            else
            {
//              opening tag
                $matches = array();
//              check to see if this is a full tag or an openclose tag
                $has_closing_tag = substr($tag['block'], -2) !== '/'.self::$tag_close;
//              perform data matches
                if($has_closing_tag === true)
                {
                    $preg = '!(\\'.self::$tag_open.$tagname.':([_\-A-Za-z0-9]*)[^\\'.self::$tag_close.']*\\'.self::$tag_close.'| \/\\'.self::$tag_close.').*\\'.self::$tag_open.'\/'.$tagname.':[_\-A-Za-z0-9]*\\'.self::$tag_close.'!is';
//                  $preg = '!(\<'.$tagname.':([_\-A-Za-z0-9]*)[^\>]*\>| \/\>).*\<\/'.$tagname.':[_\-A-Za-z0-9]*\>!is';
                }
                else
                {
                    $preg = '!(\\'.self::$tag_open.$tagname.':([_\-A-Za-z0-9]*)([^\\'.self::$tag_close.']*))!is';
//                  $preg = '!(\<'.$tagname.':([_\-A-Za-z0-9]*)([^\/\>]*))!is';
                }
                
                if(preg_match_all($preg, $tag['block'], $matches) > 0)
                {
//                  get the tag type
                    $tag['name']    = $matches[2][0];
                
//                  get the tag inner content
                    $tag['content'] = '';
                    $tag['vars'] = false;
                    $attribute_string = $matches[1][0];
                    if($has_closing_tag === true)
                    {
                        $begin_len      = strlen($matches[1][0]);
                        $end_len = $has_closing_tag ? strlen(self::$tag_open.'/'.$tagname.':'.$tag['name'].self::$tag_close) : 0;
                        $tag['content'] = substr($str, $begin_len, strlen($matches[0][0])-$begin_len-$end_len);
//                      get hash tags vars?
                        if($this->_options['hash_tags'] === true && preg_match_all('/#{([^}]+)?}/i', $tag['content'], $vars) > 0)
                        {                       
                            $variables = array();
                            foreach ($vars[0] as $key => $var)
                            {
                                $variables[$var] = $vars[1][$key]; 
                            }
                            $tag['vars'] = $variables;
                        }
                    }
                    else
                    {
                        $attribute_string = rtrim($attribute_string, '/ ');
                    }
                    
//                  get the attributes
                    $attributes = array();
//                  preg_match_all("/([_\-A-Za-z0-9]*)((=\"|='))([\w\W\s]*)(\"|')/", $opener, $attributes);
//                  preg_match_all("/([_\-A-Za-z0-9]*)((=\"|='))([_\-A-Za-z0-9]*)(\"|')/", $opener, $atts);
//                  $result = preg_match_all("!([_\-A-Za-z0-9]*)(=\"|=')([\#\s\:\.\?\&\=\%\+\,\@\_\-A-Za-z0-9]*)(\"|')!is", $matches[1][0], $attributes);
                    if(preg_match_all("!([_\-A-Za-z0-9]*)(=\")([^\"]*)(\")!is", $attribute_string, $attributes) > 0)
                    {
                        foreach($attributes[0] as $key=>$row)
                        {
                            $tag['attributes'][$attributes[1][$key]] = $attributes[3][$key];
                        }
                        if(isset($tag['attributes']['template']) === true)
                        {                                             
                            $template = $this->_options['template_directory'].$tag['name'].DIRECTORY_SEPARATOR.$tag['attributes']['template'].'.html';
                            if(is_file($template) === false)
                            {                                 
//                                $tag['attributes']['template'] = false;
                                $tag['attributes']['_template'] = $template;
                            }
                            else
                            {
                                $tag['attributes']['template'] = $template;
                            }
                        }
                    }
                } 
                $tag['attributes'] = (object) $tag['attributes'];
                return $tag;
            }
        }
1129953
protected function extractMediaFromBBCode($str)
    {
        $references = array();

        /** @var BBcodeParserInterface $parserBBcode */
        $parsedBBcode = $this->bbcodeParser->parse($str);
        $mediaTags = $parsedBBcode->getElementByTagName(AbstractMediaCodeDefinition::TAG_NAME);
        /** @var BBcodeElementNode $mediaTag */
        foreach ($mediaTags as $mediaTag) {
            $references[] = $mediaTag->getAsText();
        }

        return $references;
    }
187177
private function _decode_string(string $str): string
    {
        // init
        $regExForHtmlTags = '/<\p{L}+.*+/us';

        if (
            \strpos($str, '<') !== false
            &&
            \preg_match($regExForHtmlTags, $str, $matches) === 1
        ) {
            $str = (string) \preg_replace_callback(
                $regExForHtmlTags,
                function ($matches) {
                    return $this->_decode_entity($matches);
                },
                $str
            );
        } else {
            $str = UTF8::rawurldecode($str);
        }

        return $str;
    }
1346646
protected function parse($str)
    {
        $count = preg_match_all($this->tags->regex(), $str, $matches);

        // If we didn't find anything, return the string right back
        if (!$count || !is_array($matches)) {
            return $str;
        }

        // All we want is the array of actual strings matched
        $matches = reset($matches);

        return $this->parseTags($str, $matches);
    }
804515
protected function getNodePropertyByTagName(\DOMElement $node, $tagName, $propertyName)
    {
        $values = array();
        $results = $node->getElementsByTagName($tagName);
        if ($results->length) {
            foreach ($results as $result) {
                if ($result->getAttribute($propertyName)) {
                    $values[] = $result->getAttribute($propertyName);
                }
            }
        }

        return $values;
    }
419268
public function parse( $str ) {
        
        $this->reset();
        $parent = $this->treeRoot;
        
        $tokenManager = new TokenManager( $str );
                
        $nodeid = 1;
        $inTag = false;
        while( $tokenManager->hasCurrent() ) {
            // tokens are either "[", "]" or a string that contains neither a opening bracket nor a closing bracket
            
            if( $inTag ) {
                // this token should be a tag name
                
                // explode by = in case there's an attribute
                $pieces = explode('=', $tokenManager->getCurrent(), 2);
                
                // check if it's a closing tag
                if( substr($pieces[0], 0, 1) == "/" ) {
                    $tagName = substr($pieces[0], 1);
                    $closing = true;
                } else {
                    $tagName = $pieces[0];
                    $closing = false;
                }
                                                
                if( ($this->codeExists( $tagName, isset($pieces[1])) || $closing && $this->codeExists($tagName, true)) && $tokenManager->hasNext() && $tokenManager->next() == "]" )
                {
                    if( $closing )
                    {
                        $closestParent = $parent->closestParentOfType( $tagName );
                                                
                        if( $closestParent != null && $closestParent->hasParent() )
                        {
                            // closing an element... move to this element's parent
                            $parent->getCodeDefinition()->decrementCounter();
                            $parent = $closestParent->getParent();
                            $tokenManager->advance();
                            $tokenManager->advance();
                            $inTag = false;
                            continue;
                        }
                        
                    } else {
                        // new element
                        $el = new ElementNode();
                        $code = $this->getCode($tagName, isset($pieces[1]));
                        $code->incrementCounter();
                        $el->setNestDepth($code->getCounter());
                        $el->setCodeDefinition($code);
                        $el->setTagName( $tagName );
                        $el->setNodeId( $nodeid++ );
                        if( isset($pieces[1]) )
                            $el->setAttribute( $pieces[1] );
                        
                        $parent->addChild( $el );
                        $parent = $el;
                        $tokenManager->advance();
                        $tokenManager->advance();
                        $inTag = false;
                        continue;
                    }
                }
                
                // the opening bracket that sent us in here was really just plain text
                $node = new TextNode( "[" );
                $node->setNodeId($nodeid++);
                $parent->addChild( $node );
                $inTag = false; 
                // treat this token as regular text, and let the next if...else structure handle it as regular text
                
            }
            
            if( $tokenManager->getCurrent() == "[") {
                $inTag = true;
            }
            else {
                $node = new TextNode( $tokenManager->getCurrent() );
                $node->setNodeId($nodeid++);
                $parent->addChild( $node );
            }
            
            $tokenManager->advance();
            
        }
        
    }
228198
private function _parse_sections($str, $media_queries = array())
    {
        // Pre-process: collapse all whitespace and strip whitespace around '>',
        // '.', ':', '+', '#'

        $patterns = array("/[\\s\n]+/", "/\\s+([>.:+#])\\s+/");
        $replacements = array(" ", "\\1");
        $str = preg_replace($patterns, $replacements, $str);
        $DEBUGCSS = $this->_dompdf->getOptions()->getDebugCss();

        $sections = explode("}", $str);
        if ($DEBUGCSS) print '[_parse_sections';
        foreach ($sections as $sect) {
            $i = mb_strpos($sect, "{");
            if ($i === false) { continue; }

            //$selectors = explode(",", mb_substr($sect, 0, $i));
            $selectors = preg_split("/,(?![^\(]*\))/", mb_substr($sect, 0, $i),0, PREG_SPLIT_NO_EMPTY);
            if ($DEBUGCSS) print '[section';

            $style = $this->_parse_properties(trim(mb_substr($sect, $i + 1)));

            // Assign it to the selected elements
            foreach ($selectors as $selector) {
                $selector = trim($selector);

                if ($selector == "") {
                    if ($DEBUGCSS) print '#empty#';
                    continue;
                }
                if ($DEBUGCSS) print '#' . $selector . '#';
                //if ($DEBUGCSS) { if (strpos($selector,'p') !== false) print '!!!p!!!#'; }

                //FIXME: tag the selector with a hash of the media query to separate it from non-conditional styles (?), xpath comments are probably not what we want to do here
                if (count($media_queries) > 0) {
                    $style->set_media_queries($media_queries);
                }
                $this->add_style($selector, $style);
            }

            if ($DEBUGCSS) {
                print 'section]';
            }
        }

        if ($DEBUGCSS) {
            print '_parse_sections]';
        }
    }
100499
function ParseStr($str) {
		$this->Clear();

		$this->modifyContent($str);

		$pos = strpos($str, '@');
		while ($pos !== false) {
			$start = $pos;
			$pos++;
			$media = '';
			$count = -1;

			while(true) {
				if ($str[$pos] == '{') {
					if ($count == -1) {
						$media = substr($str, $start, ($pos-$start));
						$count = 0;
					}
					$count++;
				}
				if ($str[$pos] == '}') $count--;

				if ($count == 0) {
					$end = $pos;

					$fullmedia = substr($str, $start, ($end-$start)+1);

					$subparse = substr($fullmedia, strpos($fullmedia, '{')+1);

					$subparse = substr($subparse, 0, -1);

					$cssparser = new Css($this->prefix);
					$cssparser->SetUrl($this->thisUrl);
					$cssparser->ParseStr($subparse);
					$codestr = $cssparser->GetCSS();

					$str = str_replace($fullmedia, '', $str);
					$this->Add($media, $codestr);
					$pos = 0;
					break;
				}
				$pos++;
				if ($pos == strlen($str)) break;
			}
			$pos = strpos($str, '@', $pos);
		}

		if (preg_match_all('#([^}]*){([^}]*)}#Sis', $str, $parts)) {
			foreach($parts[1] as $key => $keystr) {
				$codestr = trim($parts[2][$key]);
				$keys = explode(',', trim($keystr));
				if(count($keys)) {
					foreach($keys as $value) {
						$value = trim($value);
						if(strlen($value)) {
							$this->Add($value, $codestr);
						}
					}
				}
			}
		}
		return (count($this->css) > 0);
	}
1213847
public function removeTags($tagName = null) {
		$this->tags = $this->tags->filter(function ($tag) use ($tagName) {
			return $tagName !== $tag->getTagName();
		});
	}
556111
public function replaceTags($str, $tags)
    {
        return preg_replace_callback(
            '/\\{([^{}]+)\}/',
            function ($matches) use ($tags) {
                return array_key_exists($matches[1], $tags)
                ? $tags[$matches[1]]
                : '';
            },
            $str
        );
    }
461042
function parse($str) {
		preg_match_all('/(\w+)\h*=\h*(.+?)(?=,|$)/',
			$str,$pairs,PREG_SET_ORDER);
		$out=array();
		foreach ($pairs as $pair)
			$out[$pair[1]]=trim($pair[2]);
		return $out;
	}
1169911
public static function tag($tag, array $attrs, $inner=null) {
		$str = '';

		foreach($attrs as $k=>$v) {
			if(is_numeric($k))
				$str .= $v.' ';
			else
				$str .= $k.'="'.$v.'" ';
		}

		$str = '<'.$tag.' '.trim($str).'>';

		if($inner === null)
			return $str;

		$str .= $inner;

		return $str.'</'.$tag.'>';
	}
548594
function(tagName, attributes, content) {
      var el = document.createElement(tagName);
      if (attributes) {
        Parse.$(el).attr(attributes);
      }
      if (content) {
        Parse.$(el).html(content);
      }
      return el;
    }
585006
static function proper_parse_str($str)
	{
		// result array
		$arr = array();

		// split on outer delimiter
		$pairs = explode('&', $str);

		// loop through each pair
		foreach ($pairs as $i)
		{
			// split into name and value
			list($name,$value) = explode('=', $i, 2);

			// if name already exists
			if( isset($arr[$name]) )
			{
				// stick multiple values into an array
				if( is_array($arr[$name]) )
					$arr[$name][] = $value;
				else
					$arr[$name] = array($arr[$name], $value);
			}
			// otherwise, simply stick it in a scalar
			else
				$arr[$name] = $value;
		}

		// return result array
		return $arr;
	}
1053146
private function parse_tag(string $text){
		$res = [];
		$text = $this->clear_text($text);
		$tag_end = strpos($text, ' ');
		if ( $tag_end !== false ){
			// Get tag
			$res['tag'] = substr($text, 1, $tag_end - 1);
			if ( in_array($res['tag'], array_keys($this->tags)) ){
        if (
          $this->tag_has_text($res['tag']) &&
          ($text = substr($text, $tag_end + 1))
        ){
          $res['text'] = $this->clear_text($text);
        }
				else {
					// Get type
					if (
            $this->tag_has_type($res['tag']) &&
            ($type = $this->tag_get_type($text)) &&
            !empty($type[1])
          ){
						$res['type'] = $type[1][0];
					}
					// Get default value
					if (
            $this->tag_has_default($res['tag']) &&
            ($def = $this->tag_get_default($text)) &&
            !empty($def[1])
          ){
						$res['default'] = $def[1][0];
					}
					// Get name
					if ( isset($def[1]) ){
						$n = $def[0][1] + strlen($def[0][0]) + 1;
					}
					else if ( isset($type[1]) ){
						$n = $type[0][1] + strlen($type[0][0]) + 1;
					}
					else {
						$n = $tag_end + 1;
					}
					if (
            $this->tag_has_name($res['tag']) &&
						($name = $this->tag_get_name(substr($text, $n)))
					){
						$res['name'] = $this->clear_text($name[0][0]);
					}
					// Get description
					if ( isset($name[0]) ){
						$d = $n + $name[0][1] + strlen($name[0][0]) + 1;
					}
					else if ( isset($type[1]) ){
						$d = $type[0][1] + strlen($type[0][0]) + 1;
					}
          else {
						$d = $tag_end + 1;
					}
					if (
            $this->tag_has_desc($res['tag']) &&
            ($desc = substr($text, $d))
          ){
						$res['description'] = $this->clear_text($desc);
					}
				}

				return $res;
			}
		}
		return false;
	}
25280
protected function getNodeValuesByTagName(DOMElement $node, $tagName)
    {
        $values = array();
        $results = $node->getElementsByTagName($tagName);
        if ($results->length) {
            foreach ($results as $result) {
                if ($result->nodeValue) {
                    $values[] = $result->nodeValue;
                }
            }
        }

        return $values;
    }
4483
public function tag($tag, $attr = null, $content = null, $close = false)
    {
        $tag = strtolower($tag);

        if (! empty($attr) && is_array($attr)) {
            $attr = $this->Attr->attr($attr);
        }

        if ($close) {
            return sprintf('<%s%s>%s</%1$s>', $tag, $attr, $content);
        } else {
            return sprintf('<%s%s>', $tag, $attr);
        }
    }