', '\#', '\+', '\-', '\.', '\!'); foreach ($escape_sequences as $index => $escape_sequence) { if (strpos($text, $escape_sequence) !== FALSE) { $code = "\x1A".'\\'.$index; $text = str_replace($escape_sequence, $code, $text); $this->escape_sequence_map[$code] = $escape_sequence; } } } # Extracts link references. if (preg_match_all('/^[ ]{0,3}\[(.+)\][ ]?:[ ]*\n?[ ]*(.+)$/m', $text, $matches, PREG_SET_ORDER)) { foreach ($matches as $matches) { $this->reference_map[strtolower($matches[1])] = $matches[2]; $text = str_replace($matches[0], '', $text); } } # ~ $text = trim($text, "\n"); $text = preg_replace('/\n\s*\n/', "\n\n", $text); $text = $this->parse_lines($text); # Decodes escape sequences (leaves out backslashes). foreach ($this->escape_sequence_map as $code => $escape_sequence) { $text = str_replace($code, $escape_sequence[1], $text); } $text = rtrim($text, "\n"); return $text; } # # Private Methods # private function parse_lines($text, $context = null) { $lines = explode("\n", $text); $lines []= NULL; $line_count = count($lines); $markup = ''; foreach ($lines as $index => $line) { # Quick Line if (isset($line) and $line !== '' and $line[0] >= 'A') { $quick_line = $line; unset($line); } # Setext Heading (-) if (isset($line) and $line !== '' and isset($paragraph) and preg_match('/^[-]+[ ]*$/', $line)) { $setext_heading_text = $this->parse_inline_elements($paragraph); $markup .= '
'.$code_block_text.'
'."\n";
unset($code_block);
}
}
# Quote Block
if (isset($line) and $line !== '' and preg_match('/^[ ]*>[ ]?(.*)/', $line, $matches))
{
if (isset($blockquote))
{
$blockquote .= "\n".$matches[1];
}
else
{
$blockquote = $matches[1];
}
unset($line);
}
elseif (isset($blockquote))
{
if (isset($line) and $line === '')
{
$blockquote .= "\n";
}
else
{
$blockquote = $this->parse_lines($blockquote);
$markup .= ''."\n".$blockquote.''."\n"; unset($blockquote); } } # Atx Heading if (isset($line) and $line !== '' and $line[0] === '#' and preg_match('/^(#{1,6})[ ]*(.+?)[ ]*#*$/', $line, $matches)) { $atx_heading_level = strlen($matches[1]); $atx_heading = $this->parse_inline_elements($matches[2]); unset($line); } elseif (isset($atx_heading)) { $markup .= '
'.$paragraph_text.'
'."\n"; } else { $markup .= ''.$paragraph_text.'
'."\n"; } unset($paragraph); } } return $markup; } private function parse_inline_elements($text) { $map = array(); $index = 0; # Code Span if (strpos($text, '`') !== FALSE and preg_match_all('/`(.+?)`/', $text, $matches, PREG_SET_ORDER)) { foreach ($matches as $matches) { $element_text = $matches[1]; $element_text = htmlentities($element_text, ENT_NOQUOTES); # Decodes escape sequences. $this->escape_sequence_map and strpos($element_text, "\x1A") !== FALSE and $element_text = strtr($element_text, $this->escape_sequence_map); # Composes element. $element = ''.$element_text.'
';
# Encodes element.
$code = "\x1A".'$'.$index;
$text = str_replace($matches[0], $code, $text);
$map[$code] = $element;
$index ++;
}
}
# Reference(d) Link / Image
if ($this->reference_map and strpos($text, '[') !== FALSE and preg_match_all('/(!?)\[(.+?)\](?:\n?[ ]?\[(.*?)\])?/ms', $text, $matches, PREG_SET_ORDER))
{
foreach ($matches as $matches)
{
$link_difinition = isset($matches[3]) && $matches[3]
? $matches[3]
: $matches[2]; # implicit
$link_difinition = strtolower($link_difinition);
if (isset($this->reference_map[$link_difinition]))
{
$url = $this->reference_map[$link_difinition];
if ($matches[1]) # image
{
$element = '';
}
else # anchor
{
$element_text = $this->parse_inline_elements($matches[2]);
$element = ''.$element_text.'';
}
# ~
$code = "\x1A".'$'.$index;
$text = str_replace($matches[0], $code, $text);
$map[$code] = $element;
$index ++;
}
}
}
# Inline Link / Image
if (strpos($text, '](') !== FALSE and preg_match_all('/(!?)(\[((?:[^][]+|(?2))*)\])\((.*?)\)/', $text, $matches, PREG_SET_ORDER)) # inline
{
foreach ($matches as $matches)
{
if ($matches[1]) # image
{
$element = '';
}
else
{
$element_text = $this->parse_inline_elements($matches[3]);
$element = ''.$element_text.'';
}
$element_text = $this->parse_inline_elements($matches[1]);
# ~
$code = "\x1A".'$'.$index;
$text = str_replace($matches[0], $code, $text);
$map[$code] = $element;
$index ++;
}
}
if (strpos($text, '<') !== FALSE and preg_match_all('/<((https?|ftp|dict):[^\^\s]+?)>/i', $text, $matches, PREG_SET_ORDER))
{
foreach ($matches as $matches)
{
$element = ':text';
$element = str_replace(':text', $matches[1], $element);
$element = str_replace(':href', $matches[1], $element);
# ~
$code = "\x1A".'$'.$index;
$text = str_replace($matches[0], $code, $text);
$map[$code] = $element;
$index ++;
}
}
if (strpos($text, '_') !== FALSE)
{
$text = preg_replace('/__(?=\S)(.+?)(?<=\S)__/', '$1', $text);
$text = preg_replace('/_(?=\S)(.+?)(?<=\S)_/', '$1', $text);
}
if (strpos($text, '*') !== FALSE)
{
$text = preg_replace('/\*\*(?=\S)(.+?)(?<=\S)\*\*/', '$1', $text);
$text = preg_replace('/\*(?=\S)(.+?)(?<=\S)\*/', '$1', $text);
}
$text = strtr($text, $map);
return $text;
}
}