parseBold($markdownString);
// Basic parsing for italic (surrounding text with *)
$markdownString = $this->parseItalic($markdownString);
// Table parsing
$markdownString = $this->parseTables($markdownString);
// Horizontal line parsing (--- or *** or ___)
$markdownString = $this->horizontalLinesParsing($markdownString);
// Basic parsing for headers (lines starting with #)
$markdownString = $this->parseHeaders($markdownString);
// Basic parsing for ordered lists
$markdownString = $this->parseOrderedLists($markdownString);
// Basic parsing for unordered lists
$markdownString = $this->parseUnorderedLists($markdownString);
// Code block parsing (lines surrounded with ``` or indented with 4 spaces)
$markdownString = $this->parseCodeBlocks($markdownString);
// Blockquote parsing (lines starting with >)
$markdownString = $this->parseBlockquote($markdownString);
// Link parsing ([text](url))
$markdownString = $this->parseLinks($markdownString);
// Image parsing ()
$markdownString = $this->parseImages($markdownString);
return $markdownString;
}
private function parseHeaders($input)
{
return preg_replace_callback('/^(#+)(.*)/m', function ($matches) {
$level = strlen($matches[1]);
return "{$matches[2]}";
}, $input);
}
private function parseBold($input)
{
return preg_replace('/\*\*(.+?)\*\*/', '$1', $input);
}
private function parseItalic($input)
{
return preg_replace('/\*(.+[^*])\*/', '$1', $input);
}
function parseOrderedLists($input){
$html = preg_replace_callback('/^\s*(\d+)\.\s*(.*)(\n\s*\d+\.\s*.*)*/m', function ($matches) {
$listItems = array_map('trim', explode("\n", $matches[0]));
$listItems = array_map(function ($item) {
return preg_replace('/^\d+\.\s*/', '', $item); // Remove the number and dot at the beginning
}, $listItems);
return '
- ' . implode('
- ', $listItems) . '
';
}, $input);
return $html;
}
function parseUnorderedLists($input){
// Match contiguous lines starting with *, -, or + as list items
$html = preg_replace_callback('/^\s*([-*+])\s*(.*)(\n\s*[-*+]\s*.*)*/m', function ($matches) {
$listItems = array_map('trim', explode("\n", $matches[0]));
$listItems = array_map(function ($item) {
return preg_replace('/^[-*+]\s*/', '', $item); // Remove the *, -, or + at the beginning
}, $listItems);
return '- ' . implode('
- ', $listItems) . '
';
}, $input);
return $html;
}
private function parseCodeBlocks($input)
{
$input = preg_replace_callback('/```(.+?)```/s', function ($matches) {
return "{$matches[1]}
";
}, $input);
$input = preg_replace_callback('/^\s{4}(.+)$/m', function ($matches) {
return "{$matches[1]}
";
}, $input);
return $input;
}
private function parseBlockquote($input)
{
return preg_replace_callback('/^\s*>\s*(.*)/m', function ($matches) {
return "{$matches[1]}
";
}, $input);
}
private function parseLinks($input)
{
return preg_replace('/\[(.*?)\]\((.*?)\)/', '$1', $input);
}
private function parseImages($input)
{
return preg_replace('/!\[(.*?)\]\((.*?)\)/', '
', $input);
}
private function horizontalLinesParsing($input){
return preg_replace('/^(.*?)(---|___|\*\*\*)(.*?)$/m', '$1
$3', $input);
}
private function parseTables($input)
{
$tables = [];
$currentTable = '';
$inTable = false;
$lines = explode("\n", $input);
foreach ($lines as $line) {
if (preg_match('/^\s*\|(.+)\|\s*$/', $line, $matches)) {
$tableRow = trim($matches[1]);
$columns = explode('|', $tableRow);
$columns = array_map('trim', $columns);
// Skip lines with only dashes or empty columns
if (preg_match('/^\s*-{3,}\s*$/', $columns[0])) {
$inTable = true;
continue;
}
$tableHtml = '';
if (!$inTable) {
$tableHtml .= '';
}
$tableHtml .= '';
foreach ($columns as $column) {
$cellTag = $inTable ? 'td' : 'th';
$tableHtml .= "<$cellTag>$column$cellTag>";
}
$tableHtml .= '
';
$currentTable .= $tableHtml;
} else {
if ($inTable) {
$currentTable .= '
';
$tables[] = $currentTable;
$currentTable = '';
$inTable = false;
}
$tables[] = $line;
}
}
// Check if there's a remaining table
if ($inTable && !empty($currentTable)) {
$currentTable .= '';
$tables[] = $currentTable;
}
return implode("\n", $tables);
}
}