:
- $text = preg_replace_callback(
- '{ ( (?runSpanGamut($text);
- return $this->hashPart("$text");
+ var $em_relist = array(
+ '' => '(?:(? '(?<=\S|^)(? '(?<=\S|^)(? '(?:(? '(?<=\S|^)(? '(?<=\S|^)(? '(?:(? '(?<=\S|^)(? '(?<=\S|^)(?em_relist as $em => $em_re) {
+ foreach ($this->strong_relist as $strong => $strong_re) {
+ # Construct list of allowed token expressions.
+ $token_relist = array();
+ if (isset($this->em_strong_relist["$em$strong"])) {
+ $token_relist[] = $this->em_strong_relist["$em$strong"];
+ }
+ $token_relist[] = $em_re;
+ $token_relist[] = $strong_re;
+
+ # Construct master expression from list.
+ $token_re = '{('. implode('|', $token_relist) .')}';
+ $this->em_strong_prepared_relist["$em$strong"] = $token_re;
+ }
+ }
}
- function _doItalicAndBold_strong_callback($matches) {
- $text = $matches[2];
- $text = $this->runSpanGamut($text);
- return $this->hashPart("$text");
+
+ function doItalicsAndBold($text) {
+ $token_stack = array('');
+ $text_stack = array('');
+ $em = '';
+ $strong = '';
+ $tree_char_em = false;
+
+ while (1) {
+ #
+ # Get prepared regular expression for seraching emphasis tokens
+ # in current context.
+ #
+ $token_re = $this->em_strong_prepared_relist["$em$strong"];
+
+ #
+ # Each loop iteration search for the next emphasis token.
+ # Each token is then passed to handleSpanToken.
+ #
+ $parts = preg_split($token_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
+ $text_stack[0] .= $parts[0];
+ $token =& $parts[1];
+ $text =& $parts[2];
+
+ if (empty($token)) {
+ # Reached end of text span: empty stack without emitting.
+ # any more emphasis.
+ while ($token_stack[0]) {
+ $text_stack[1] .= array_shift($token_stack);
+ $text_stack[0] .= array_shift($text_stack);
+ }
+ break;
+ }
+
+ $token_len = strlen($token);
+ if ($tree_char_em) {
+ # Reached closing marker while inside a three-char emphasis.
+ if ($token_len == 3) {
+ # Three-char closing marker, close em and strong.
+ array_shift($token_stack);
+ $span = array_shift($text_stack);
+ $span = $this->runSpanGamut($span);
+ $span = "$span";
+ $text_stack[0] .= $this->hashPart($span);
+ $em = '';
+ $strong = '';
+ } else {
+ # Other closing marker: close one em or strong and
+ # change current token state to match the other
+ $token_stack[0] = str_repeat($token{0}, 3-$token_len);
+ $tag = $token_len == 2 ? "strong" : "em";
+ $span = $text_stack[0];
+ $span = $this->runSpanGamut($span);
+ $span = "<$tag>$span$tag>";
+ $text_stack[0] = $this->hashPart($span);
+ $$tag = ''; # $$tag stands for $em or $strong
+ }
+ $tree_char_em = false;
+ } else if ($token_len == 3) {
+ if ($em) {
+ # Reached closing marker for both em and strong.
+ # Closing strong marker:
+ for ($i = 0; $i < 2; ++$i) {
+ $shifted_token = array_shift($token_stack);
+ $tag = strlen($shifted_token) == 2 ? "strong" : "em";
+ $span = array_shift($text_stack);
+ $span = $this->runSpanGamut($span);
+ $span = "<$tag>$span$tag>";
+ $text_stack[0] .= $this->hashPart($span);
+ $$tag = ''; # $$tag stands for $em or $strong
+ }
+ } else {
+ # Reached opening three-char emphasis marker. Push on token
+ # stack; will be handled by the special condition above.
+ $em = $token{0};
+ $strong = "$em$em";
+ array_unshift($token_stack, $token);
+ array_unshift($text_stack, '');
+ $tree_char_em = true;
+ }
+ } else if ($token_len == 2) {
+ if ($strong) {
+ # Unwind any dangling emphasis marker:
+ if (strlen($token_stack[0]) == 1) {
+ $text_stack[1] .= array_shift($token_stack);
+ $text_stack[0] .= array_shift($text_stack);
+ }
+ # Closing strong marker:
+ array_shift($token_stack);
+ $span = array_shift($text_stack);
+ $span = $this->runSpanGamut($span);
+ $span = "$span";
+ $text_stack[0] .= $this->hashPart($span);
+ $strong = '';
+ } else {
+ array_unshift($token_stack, $token);
+ array_unshift($text_stack, '');
+ $strong = $token;
+ }
+ } else {
+ # Here $token_len == 1
+ if ($em) {
+ if (strlen($token_stack[0]) == 1) {
+ # Closing emphasis marker:
+ array_shift($token_stack);
+ $span = array_shift($text_stack);
+ $span = $this->runSpanGamut($span);
+ $span = "$span";
+ $text_stack[0] .= $this->hashPart($span);
+ $em = '';
+ } else {
+ $text_stack[0] .= $token;
+ }
+ } else {
+ array_unshift($token_stack, $token);
+ array_unshift($text_stack, '');
+ $em = $token;
+ }
+ }
+ }
+ return $text_stack[0];
}
@@ -1050,7 +1188,7 @@ class Markdown_Parser {
# These leading spaces cause problem with content,
# so we need to fix that:
$bq = preg_replace_callback('{(\s*.+?
)}sx',
- array(&$this, '_DoBlockQuotes_callback2'), $bq);
+ array(&$this, '_doBlockQuotes_callback2'), $bq);
return "\n". $this->hashBlock("\n$bq\n
")."\n\n";
}
@@ -1133,7 +1271,8 @@ class Markdown_Parser {
function encodeAttribute($text) {
#
- # Encode text for a double-quoted HTML attribute.
+ # Encode text for a double-quoted HTML attribute. This function
+ # is *not* suitable for attributes enclosed in single quotes.
#
$text = $this->encodeAmpsAndAngles($text);
$text = str_replace('"', '"', $text);
@@ -1142,20 +1281,21 @@ class Markdown_Parser {
function encodeAmpsAndAngles($text) {
- # Smart processing for ampersands and angle brackets that need to be encoded.
+ #
+ # Smart processing for ampersands and angle brackets that need to
+ # be encoded. Valid character entities are left alone unless the
+ # no-entities mode is set.
+ #
if ($this->no_entities) {
$text = str_replace('&', '&', $text);
- $text = str_replace('<', '<', $text);
- return $text;
+ } else {
+ # Ampersand-encoding based entirely on Nat Irons's Amputator
+ # MT plugin:
+ $text = preg_replace('/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/',
+ '&', $text);;
}
-
- # Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:
- # http://bumppo.net/projects/amputator/
- $text = preg_replace('/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/',
- '&', $text);;
-
- # Encode naked <'s
- $text = preg_replace('{<(?![a-z/?\$!%])}i', '<', $text);
+ # Encode remaining <'s
+ $text = str_replace('<', '<', $text);
return $text;
}
@@ -1170,9 +1310,17 @@ class Markdown_Parser {
<
(?:mailto:)?
(
- [-.\w\x80-\xFF]+
+ (?:
+ [-!#$%&\'*+/=?^_`.{|}~\w\x80-\xFF]+
+ |
+ ".*?"
+ )
\@
- [-a-z0-9\x80-\xFF]+(\.[-a-z0-9\x80-\xFF]+)*\.[a-z]+
+ (?:
+ [-a-z0-9\x80-\xFF]+(\.[-a-z0-9\x80-\xFF]+)*\.[a-z]+
+ |
+ \[[\d.a-fA-F:]+\] # IPv4 & IPv6
+ )
)
>
}xi',
@@ -1240,9 +1388,9 @@ class Markdown_Parser {
#
$output = '';
- $regex = '{
+ $span_re = '{
(
- \\\\['.preg_quote($this->escape_chars).']
+ \\\\'.$this->escape_chars_re.'
|
(? | <%.*?%> # processing instruction
|
- <[/!$]?[-a-zA-Z0-9:]+ # regular tags
+ <[/!$]?[-a-zA-Z0-9:_]+ # regular tags
(?>
\s
(?>[^"\'>]+|"[^"]*"|\'[^\']*\')*
@@ -1268,7 +1416,7 @@ class Markdown_Parser {
# openning code span marker, or the next escaped character.
# Each token is then passed to handleSpanToken.
#
- $parts = preg_split($regex, $str, 2, PREG_SPLIT_DELIM_CAPTURE);
+ $parts = preg_split($span_re, $str, 2, PREG_SPLIT_DELIM_CAPTURE);
# Create token from text preceding tag.
if ($parts[0] != "") {
@@ -1299,7 +1447,7 @@ class Markdown_Parser {
return $this->hashPart("". ord($token{1}). ";");
case "`":
# Search for end marker in remaining text.
- if (preg_match('/^(.*?[^`])'.$token.'(?!`)(.*)$/sm',
+ if (preg_match('/^(.*?[^`])'.preg_quote($token).'(?!`)(.*)$/sm',
$str, $matches))
{
$str = $matches[2];
@@ -1415,6 +1563,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
# Insert extra document, block, and span transformations.
# Parent constructor will do the sorting.
$this->document_gamut += array(
+ "doFencedCodeBlocks" => 5,
"stripFootnotes" => 15,
"stripAbbreviations" => 25,
"appendFootnotes" => 50,
@@ -1433,11 +1582,11 @@ class MarkdownExtra_Parser extends Markdown_Parser {
}
- # Extra hashes used during extra transformations.
+ # Extra variables used during extra transformations.
var $footnotes = array();
var $footnotes_ordered = array();
var $abbr_desciptions = array();
- var $abbr_matches = array();
+ var $abbr_word_re = '';
# Give the current footnote number.
var $footnote_counter = 1;
@@ -1452,11 +1601,13 @@ class MarkdownExtra_Parser extends Markdown_Parser {
$this->footnotes = array();
$this->footnotes_ordered = array();
$this->abbr_desciptions = array();
- $this->abbr_matches = array();
+ $this->abbr_word_re = '';
$this->footnote_counter = 1;
foreach ($this->predef_abbr as $abbr_word => $abbr_desc) {
- $this->abbr_matches[] = preg_quote($abbr_word);
+ if ($this->abbr_word_re)
+ $this->abbr_word_re .= '|';
+ $this->abbr_word_re .= preg_quote($abbr_word);
$this->abbr_desciptions[$abbr_word] = trim($abbr_desc);
}
}
@@ -1468,7 +1619,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
$this->footnotes = array();
$this->footnotes_ordered = array();
$this->abbr_desciptions = array();
- $this->abbr_matches = array();
+ $this->abbr_word_re = '';
parent::teardown();
}
@@ -1477,20 +1628,20 @@ class MarkdownExtra_Parser extends Markdown_Parser {
### HTML Block Parser ###
# Tags that are always treated as block tags:
- var $block_tags = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|form|fieldset|iframe|hr|legend';
+ var $block_tags_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|form|fieldset|iframe|hr|legend';
# Tags treated as block tags only if the opening tag is alone on it's line:
- var $context_block_tags = 'script|noscript|math|ins|del';
+ var $context_block_tags_re = 'script|noscript|math|ins|del';
# Tags where markdown="1" default to span mode:
- var $contain_span_tags = 'p|h[1-6]|li|dd|dt|td|th|legend|address';
+ var $contain_span_tags_re = 'p|h[1-6]|li|dd|dt|td|th|legend|address';
# Tags which must not have their contents modified, no matter where
# they appear:
- var $clean_tags = 'script|math';
+ var $clean_tags_re = 'script|math';
# Tags that do not need to be closed.
- var $auto_close_tags = 'hr|img';
+ var $auto_close_tags_re = 'hr|img';
function hashHTMLBlocks($text) {
@@ -1517,7 +1668,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
return $text;
}
function _hashHTMLBlocks_inMarkdown($text, $indent = 0,
- $enclosing_tag = '', $span = false)
+ $enclosing_tag_re = '', $span = false)
{
#
# Parse markdown text, calling _HashHTMLBlocks_InHTML for block tags.
@@ -1535,7 +1686,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
# If you don't like this, just don't indent the tag on which
# you apply the markdown="1" attribute.
#
- # * If $enclosing_tag is not empty, stops at the first unmatched closing
+ # * If $enclosing_tag_re is not empty, stops at the first unmatched closing
# tag with that name. Nested tags supported.
#
# * If $span is true, text inside must treated as span. So any double
@@ -1547,8 +1698,8 @@ class MarkdownExtra_Parser extends Markdown_Parser {
if ($text === '') return array('', '');
# Regex to check for the presense of newlines around a block tag.
- $newline_match_before = '/(?:^\n?|\n\n)*$/';
- $newline_match_after =
+ $newline_before_re = '/(?:^\n?|\n\n)*$/';
+ $newline_after_re =
'{
^ # Start of text following the tag.
(?>[ ]*)? # Optional comment.
@@ -1556,18 +1707,18 @@ class MarkdownExtra_Parser extends Markdown_Parser {
}xs';
# Regex to match any tag.
- $block_tag_match =
+ $block_tag_re =
'{
( # $2: Capture hole tag.
? # Any opening or closing tag.
(?> # Tag name.
- '.$this->block_tags.' |
- '.$this->context_block_tags.' |
- '.$this->clean_tags.' |
- (?!\s)'.$enclosing_tag.'
+ '.$this->block_tags_re.' |
+ '.$this->context_block_tags_re.' |
+ '.$this->clean_tags_re.' |
+ (?!\s)'.$enclosing_tag_re.'
)
(?:
- (?=[\s"\'/]) # Allowed characters after tag name.
+ (?=[\s"\'/a-zA-Z0-9]) # Allowed characters after tag name.
(?>
".*?" | # Double quotes (can contain `>`)
\'.*?\' | # Single quotes (can contain `>`)
@@ -1587,7 +1738,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
'. ( !$span ? ' # If not in span.
|
# Indented code block
- (?> ^[ ]*\n? | \n[ ]*\n )
+ (?: ^[ ]*\n | ^ | \n[ ]*\n )
[ ]{'.($indent+4).'}[^\n]* \n
(?>
(?: [ ]{'.($indent+4).'}[^\n]* | [ ]* ) \n
@@ -1615,7 +1766,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
# pattern will be at the end, and between will be any catches made
# by the pattern.
#
- $parts = preg_split($block_tag_match, $text, 2,
+ $parts = preg_split($block_tag_re, $text, 2,
PREG_SPLIT_DELIM_CAPTURE);
# If in Markdown span mode, add a empty-string span-level hash
@@ -1636,13 +1787,15 @@ class MarkdownExtra_Parser extends Markdown_Parser {
$tag = $parts[1]; # Tag to handle.
$text = $parts[2]; # Remaining text after current tag.
+ $tag_re = preg_quote($tag); # For use in a regular expression.
#
# Check for: Code span marker
#
if ($tag{0} == "`") {
# Find corresponding end marker.
- if (preg_match('{^(?>.+?|\n(?!\n))*?(?.+?|\n(?!\n))*?(?.*\n)+?'.$tag_re.' *\n}', $text,
+ $matches))
+ {
+ # End marker found: pass text unchanged until marker.
+ $parsed .= $tag . $matches[0];
+ $text = substr($text, strlen($matches[0]));
}
else {
- # Fenced code block marker: find matching end marker.
- if (preg_match('{^(?>.*\n)+?'.trim($tag).' *\n}', $text,
- $matches))
- {
- # End marker found: pass text unchanged until marker.
- $parsed .= $tag . $matches[0];
- $text = substr($text, strlen($matches[0]));
- }
- else {
- # No end marker: just skip it.
- $parsed .= $tag;
- }
+ # No end marker: just skip it.
+ $parsed .= $tag;
}
}
#
# Check for: Opening Block level tag or
- # Opening Content Block tag (like ins and del)
+ # Opening Context Block tag (like ins and del)
# used as a block tag (tag is alone on it's line).
#
- else if (preg_match("{^<(?:$this->block_tags)\b}", $tag) ||
- ( preg_match("{^<(?:$this->context_block_tags)\b}", $tag) &&
- preg_match($newline_match_before, $parsed) &&
- preg_match($newline_match_after, $text) )
+ else if (preg_match('{^<(?:'.$this->block_tags_re.')\b}', $tag) ||
+ ( preg_match('{^<(?:'.$this->context_block_tags_re.')\b}', $tag) &&
+ preg_match($newline_before_re, $parsed) &&
+ preg_match($newline_after_re, $text) )
)
{
# Need to parse tag and following text using the HTML parser.
@@ -1700,7 +1855,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
# Check for: Clean tag (like script, math)
# HTML Comments, processing instructions.
#
- else if (preg_match("{^<(?:$this->clean_tags)\b}", $tag) ||
+ else if (preg_match('{^<(?:'.$this->clean_tags_re.')\b}', $tag) ||
$tag{1} == '!' || $tag{1} == '?')
{
# Need to parse tag and following text using the HTML parser.
@@ -1713,9 +1868,9 @@ class MarkdownExtra_Parser extends Markdown_Parser {
#
# Check for: Tag with same name as enclosing tag.
#
- else if ($enclosing_tag !== '' &&
+ else if ($enclosing_tag_re !== '' &&
# Same name as enclosing tag.
- preg_match("{^?(?:$enclosing_tag)\b}", $tag))
+ preg_match('{^?(?:'.$enclosing_tag_re.')\b}', $tag))
{
#
# Increase/decrease nested tag count.
@@ -1755,7 +1910,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
if ($text === '') return array('', '');
# Regex to match `markdown` attribute inside of a tag.
- $markdown_attr_match = '
+ $markdown_attr_re = '
{
\s* # Eat whitespace before the `markdown` attribute
markdown
@@ -1771,12 +1926,12 @@ class MarkdownExtra_Parser extends Markdown_Parser {
}xs';
# Regex to match any tag.
- $tag_match = '{
+ $tag_re = '{
( # $2: Capture hole tag.
? # Any opening or closing tag.
[\w:$]+ # Tag name.
(?:
- (?=[\s"\'/]) # Allowed characters after tag name.
+ (?=[\s"\'/a-zA-Z0-9]) # Allowed characters after tag name.
(?>
".*?" | # Double quotes (can contain `>`)
\'.*?\' | # Single quotes (can contain `>`)
@@ -1801,9 +1956,10 @@ class MarkdownExtra_Parser extends Markdown_Parser {
#
# Get the name of the starting tag.
+ # (This pattern makes $base_tag_name_re safe without quoting.)
#
- if (preg_match("/^<([\w:$]*)\b/", $text, $matches))
- $base_tag_name = $matches[1];
+ if (preg_match('/^<([\w:$]*)\b/', $text, $matches))
+ $base_tag_name_re = $matches[1];
#
# Loop through every tag until we find the corresponding closing tag.
@@ -1815,7 +1971,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
# pattern will be at the end, and between will be any catches made
# by the pattern.
#
- $parts = preg_split($tag_match, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
+ $parts = preg_split($tag_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
if (count($parts) < 3) {
#
@@ -1835,7 +1991,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
# Check for: Auto-close tag (like
)
# Comments and Processing Instructions.
#
- if (preg_match("{^?(?:$this->auto_close_tags)\b}", $tag) ||
+ if (preg_match('{^?(?:'.$this->auto_close_tags_re.')\b}', $tag) ||
$tag{1} == '!' || $tag{1} == '?')
{
# Just add the tag to the block as if it was text.
@@ -1846,7 +2002,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
# Increase/decrease nested tag count. Only do so if
# the tag's name match base tag's.
#
- if (preg_match("{^?$base_tag_name\b}", $tag)) {
+ if (preg_match('{^?'.$base_tag_name_re.'\b}', $tag)) {
if ($tag{1} == '/') $depth--;
else if ($tag{strlen($tag)-2} != '/') $depth++;
}
@@ -1855,16 +2011,16 @@ class MarkdownExtra_Parser extends Markdown_Parser {
# Check for `markdown="1"` attribute and handle it.
#
if ($md_attr &&
- preg_match($markdown_attr_match, $tag, $attr_m) &&
+ preg_match($markdown_attr_re, $tag, $attr_m) &&
preg_match('/^1|block|span$/', $attr_m[2] . $attr_m[3]))
{
# Remove `markdown` attribute from opening tag.
- $tag = preg_replace($markdown_attr_match, '', $tag);
+ $tag = preg_replace($markdown_attr_re, '', $tag);
# Check if text inside this tag must be parsed in span mode.
$this->mode = $attr_m[2] . $attr_m[3];
$span_mode = $this->mode == 'span' || $this->mode != 'block' &&
- preg_match("{^<(?:$this->contain_span_tags)\b}", $tag);
+ preg_match('{^<(?:'.$this->contain_span_tags_re.')\b}', $tag);
# Calculate indent before tag.
if (preg_match('/(?:^|\n)( *?)(?! ).*?$/', $block_text, $matches)) {
@@ -1879,13 +2035,14 @@ class MarkdownExtra_Parser extends Markdown_Parser {
$parsed .= $this->$hash_method($block_text);
# Get enclosing tag name for the ParseMarkdown function.
+ # (This pattern makes $tag_name_re safe without quoting.)
preg_match('/^<([\w:$]*)\b/', $tag, $matches);
- $tag_name = $matches[1];
+ $tag_name_re = $matches[1];
# Parse the content using the HTML-in-Markdown parser.
list ($block_text, $text)
= $this->_hashHTMLBlocks_inMarkdown($text, $indent,
- $tag_name, $span_mode);
+ $tag_name_re, $span_mode);
# Outdent markdown text.
if ($indent > 0) {
@@ -1969,6 +2126,8 @@ class MarkdownExtra_Parser extends Markdown_Parser {
return " id=\"$attr\"";
}
function _doHeaders_callback_setext($matches) {
+ if ($matches[3] == '-' && preg_match('{^- }', $matches[1]))
+ return $matches[0];
$level = $matches[3]{0} == '=' ? 1 : 2;
$attr = $this->_doHeaders_attr($id =& $matches[2]);
$block = "".$this->runSpanGamut($matches[1])."";
@@ -2119,7 +2278,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
$less_than_tab = $this->tab_width - 1;
# Re-usable pattern to match any entire dl list:
- $whole_list = '(?>
+ $whole_list_re = '(?>
( # $1 = whole list
( # $2
[ ]{0,'.$less_than_tab.'}
@@ -2148,7 +2307,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
$text = preg_replace_callback('{
(?>\A\n?|(?<=\n\n))
- '.$whole_list.'
+ '.$whole_list_re.'
}mx',
array(&$this, '_doDefLists_callback'), $text);
@@ -2285,63 +2444,25 @@ class MarkdownExtra_Parser extends Markdown_Parser {
}
- function doItalicsAndBold($text) {
#
- # Redefined to change emphasis by underscore behaviour so that it does not
+ # Redefining emphasis markers so that emphasis by underscore does not
# work in the middle of a word.
#
- # must go first:
- $text = preg_replace_callback(array(
- '{
- ( # $1: Marker
- (?
- [^_]+? # Anthing not em markers.
- |
- # Balence any regular _ emphasis inside.
- (?
- [^*]+? # Anthing not em markers.
- |
- # Balence any regular * emphasis inside.
- \* (?=\S) (.+?) (?<=\S) \*
- |
- \* # Allow unbalenced as last resort.
- )+?
- )
- (?<=\S) \*\* # End mark not preceded by whitespace.
- }sx',
- ),
- array(&$this, '_doItalicAndBold_strong_callback'), $text);
- # Then :
- $text = preg_replace_callback(array(
- '{ ( (? '(?:(? '(?<=\S|^)(? '(?<=\S|^)(? '(?:(? '(?<=\S|^)(? '(?<=\S|^)(? '(?:(? '(?<=\S|^)(? '(?<=\S|^)(?footnotes_ordered)) {
$text .= "\n\n";
$text .= "