パーサを作成してみたい

JSでのパーサを作成してみたい

```
function parseMarkdown(markdown) {
    const rules = [
        { regex: /###### (.*?)(\n|$)/g, replacement: '<h6>$1</h6>$2' },
        { regex: /##### (.*?)(\n|$)/g, replacement: '<h5>$1</h5>$2' },
        { regex: /#### (.*?)(\n|$)/g, replacement: '<h4>$1</h4>$2' },
        { regex: /### (.*?)(\n|$)/g, replacement: '<h3>$1</h3>$2' },
        { regex: /## (.*?)(\n|$)/g, replacement: '<h2>$1</h2>$2' },
        { regex: /# (.*?)(\n|$)/g, replacement: '<h1>$1</h1>$2' },
        { regex: /\*\*\*(.*?)\*\*\*/g, replacement: '<strong><em>$1</em></strong>' },
        { regex: /\*\*(.*?)\*\*/g, replacement: '<strong>$1</strong>' },
        { regex: /\*(.*?)\*/g, replacement: '<em>$1</em>' },
        { regex: /__(.*?)__/g, replacement: '<strong>$1</strong>' },
        { regex: /_(.*?)_/g, replacement: '<em>$1</em>' },
        { regex: /```(.*?)```/gs, replacement: '<pre><code>$1</code></pre>' },
        { regex: /`(.*?)`/g, replacement: '<code>$1</code>' },
        { regex: /\n/g, replacement: '<br>' }
    ];

    // テーブル解析の追加
    const tableRegex = /((\|.*?\|)\n)+\|[\-\|]+\|\n((\|.*?\|)\n)*/g;

    function parseTable(tableMarkdown) {
        const rows = tableMarkdown.trim().split('\n');
        const header = rows[0].split('|').slice(1, -1).map(cell => cell.trim());
        const align = rows[1].split('|').slice(1, -1).map(cell => {
            if (cell.trim().startsWith(':') && cell.trim().endsWith(':')) return 'center';
            if (cell.trim().startsWith(':')) return 'left';
            if (cell.trim().endsWith(':')) return 'right';
            return 'left';
        });
        const body = rows.slice(2).map(row => row.split('|').slice(1, -1).map(cell => cell.trim()));

        let tableHtml = '<table><thead><tr>';
        header.forEach((cell, i) => {
            tableHtml += `<th style="text-align: ${align[i]}">${cell}</th>`;
        });
        tableHtml += '</tr></thead><tbody>';
        body.forEach(row => {
            tableHtml += '<tr>';
            row.forEach((cell, i) => {
                tableHtml += `<td style="text-align: ${align[i]}">${cell}</td>`;
            });
            tableHtml += '</tr>';
        });
        tableHtml += '</tbody></table>';

        return tableHtml;
    }

    let html = markdown;
    html = html.replace(tableRegex, (match) => parseTable(match));

    rules.forEach(rule => {
        html = html.replace(rule.regex, rule.replacement);
    });

    return html;
}

// テスト
const markdownText = `
# 見出し1
## 見出し2
### 見出し3

これは**太字**のテキストで、これは*イタリック*です。

これは`コード`です。

\`\`\`
これはコードブロックです
\`\`\`

| 見出し1 | 見出し2 | 見出し3 |
|:-------|:-------:|--------:|
| 左寄せ | 中央寄せ | 右寄せ |
| 左寄せ2 | 中央寄せ2 | 右寄せ2 |
`;

console.log(parseMarkdown(markdownText));

```


function parseMarkdown(markdown) {
    const rules = [
        { regex: /###### (.*?)(\n|$)/g, replacement: '<h6>$1</h6>' },
        { regex: /##### (.*?)(\n|$)/g, replacement: '<h5>$1</h5>' },
        { regex: /#### (.*?)(\n|$)/g, replacement: '<h4>$1</h4>' },
        { regex: /### (.*?)(\n|$)/g, replacement: '<h3>$1</h3>' },
        { regex: /## (.*?)(\n|$)/g, replacement: '<h2>$1</h2>' },
        { regex: /# (.*?)(\n|$)/g, replacement: '<h1>$1</h1>' },
        { regex: /\*\*\*(.*?)\*\*\*/g, replacement: '<strong><em>$1</em></strong>' },
        { regex: /\*\*(.*?)\*\*/g, replacement: '<strong>$1</strong>' },
        { regex: /\*(.*?)\*/g, replacement: '<em>$1</em>' },
        { regex: /__(.*?)__/g, replacement: '<strong>$1</strong>' },
        { regex: /_(.*?)_/g, replacement: '<em>$1</em>' },
        { regex: /```([^```]*)```/gs, replacement: '<pre><code>$1</code></pre>' },
        { regex: /`([^`]*)`/g, replacement: '<code>$1</code>' }
    ];

    const tableRegex = /((\|.*?\|)\n)+\|[\-\|]+\|\n((\|.*?\|)\n)*/g;

    function parseTable(tableMarkdown) {
        const rows = tableMarkdown.trim().split('\n');
        const header = rows[0].split('|').slice(1, -1).map(cell => cell.trim());
        const align = rows[1].split('|').slice(1, -1).map(cell => {
            if (cell.trim().startsWith(':') && cell.trim().endsWith(':')) return 'center';
            if (cell.trim().startsWith(':')) return 'left';
            if (cell.trim().endsWith(':')) return 'right';
            return 'left';
        });
        const body = rows.slice(2).map(row => row.split('|').slice(1, -1).map(cell => cell.trim()));

        let tableHtml = '<table><thead><tr>';
        header.forEach((cell, i) => {
            tableHtml += `<th style="text-align: ${align[i]}">${cell}</th>`;
        });
        tableHtml += '</tr></thead><tbody>';
        body.forEach(row => {
            tableHtml += '<tr>';
            row.forEach((cell, i) => {
                tableHtml += `<td style="text-align: ${align[i]}">${cell}</td>`;
            });
            tableHtml += '</tr>';
        });
        tableHtml += '</tbody></table>';

        return tableHtml;
    }

    const lines = markdown.split('\n');
    let html = '';
    let inCodeBlock = false;
    let inParagraph = false;

    lines.forEach(line => {
        if (line.match(/^```/)) {
            inCodeBlock = !inCodeBlock;
            html += inCodeBlock ? '<pre><code>' : '</code></pre>';
            return;
        }

        if (inCodeBlock) {
            html += line + '\n';
            return;
        }

        if (line.match(tableRegex)) {
            if (inParagraph) {
                html += '</p>';
                inParagraph = false;
            }
            html += parseTable(line);
            return;
        }

        let processedLine = line;

        rules.forEach(rule => {
            processedLine = processedLine.replace(rule.regex, rule.replacement);
        });

        if (processedLine.trim() === '') {
            if (inParagraph) {
                html += '</p>';
                inParagraph = false;
            }
        } else {
            if (!inParagraph && !processedLine.startsWith('<h')) {
                html += '<p>';
                inParagraph = true;
            }
            html += processedLine + ' ';
        }
    });

    if (inParagraph) {
        html += '</p>';
    }

    return html;
}

// テスト
const markdownText = `
# 見出し1
## 見出し2
### 見出し3

これは**太字**のテキストで、これは*イタリック*です。

これは\`コード\`です。

\`\`\`
これはコードブロックです
\`\`\`

| 見出し1 | 見出し2 | 見出し3 |
|:-------|:-------:|--------:|
| 左寄せ | 中央寄せ | 右寄せ |
| 左寄せ2 | 中央寄せ2 | 右寄せ2 |
`;

console.log(parseMarkdown(markdownText));

# kokokraa

```
function parseMarkdown(markdown) {
    const rules = [
        { regex: /###### (.*?)(\n|$)/g, replacement: '<h6>$1</h6>' },
        { regex: /##### (.*?)(\n|$)/g, replacement: '<h5>$1</h5>' },
        { regex: /#### (.*?)(\n|$)/g, replacement: '<h4>$1</h4>' },
        { regex: /### (.*?)(\n|$)/g, replacement: '<h3>$1</h3>' },
        { regex: /## (.*?)(\n|$)/g, replacement: '<h2>$1</h2>' },
        { regex: /# (.*?)(\n|$)/g, replacement: '<h1>$1</h1>' },
        { regex: /\*\*\*(.*?)\*\*\*/g, replacement: '<strong><em>$1</em></strong>' },
        { regex: /\*\*(.*?)\*\*/g, replacement: '<strong>$1</strong>' },
        { regex: /\*(.*?)\*/g, replacement: '<em>$1</em>' },
        { regex: /__(.*?)__/g, replacement: '<strong>$1</strong>' },
        { regex: /_(.*?)_/g, replacement: '<em>$1</em>' },
        { regex: /```([^```]*)```/gs, replacement: '<pre><code>$1</code></pre>' },
        { regex: /`([^`]*)`/g, replacement: '<code>$1</code>' }
    ];

    const tableRegex = /((\|.*?\|)\n)+\|[\-\|]+\|\n((\|.*?\|)\n)*/g;

    function parseTable(tableMarkdown) {
        const rows = tableMarkdown.trim().split('\n');
        const header = rows[0].split('|').slice(1, -1).map(cell => cell.trim());
        const align = rows[1].split('|').slice(1, -1).map(cell => {
            if (cell.trim().startsWith(':') && cell.trim().endsWith(':')) return 'center';
            if (cell.trim().startsWith(':')) return 'left';
            if (cell.trim().endsWith(':')) return 'right';
            return 'left';
        });
        const body = rows.slice(2).map(row => row.split('|').slice(1, -1).map(cell => cell.trim()));

        let tableHtml = '<table><thead><tr>';
        header.forEach((cell, i) => {
            tableHtml += `<th style="text-align: ${align[i]}">${cell}</th>`;
        });
        tableHtml += '</tr></thead><tbody>';
        body.forEach(row => {
            tableHtml += '<tr>';
            row.forEach((cell, i) => {
                tableHtml += `<td style="text-align: ${align[i]}">${cell}</td>`;
            });
            tableHtml += '</tr>';
        });
        tableHtml += '</tbody></table>';

        return tableHtml;
    }

    const lines = markdown.split('\n');
    let html = '';
    let inCodeBlock = false;
    let inParagraph = false;

    lines.forEach(line => {
        if (line.match(/^```/)) {
            inCodeBlock = !inCodeBlock;
            html += inCodeBlock ? '<pre><code>' : '</code></pre>';
            return;
        }

        if (inCodeBlock) {
            html += line + '\n';
            return;
        }

        if (line.match(tableRegex)) {
            if (inParagraph) {
                html += '</p>';
                inParagraph = false;
            }
            html += parseTable(line);
            return;
        }

        let processedLine = line;

        rules.forEach(rule => {
            processedLine = processedLine.replace(rule.regex, rule.replacement);
        });

        if (processedLine.trim() === '') {
            if (inParagraph) {
                html += '</p>';
                inParagraph = false;
            }
        } else {
            if (!inParagraph && !processedLine.startsWith('<h')) {
                html += '<p>';
                inParagraph = true;
            }
            html += processedLine + ' ';
        }
    });

    if (inParagraph) {
        html += '</p>';
    }

    return html;
}

// テスト
const markdownText = `
# 見出し1
## 見出し2
### 見出し3

これは**太字**のテキストで、これは*イタリック*です。

これは\`コード\`です。

\`\`\`
これはコードブロックです
\`\`\`

| 見出し1 | 見出し2 | 見出し3 |
|:-------|:-------:|--------:|
| 左寄せ | 中央寄せ | 右寄せ |
| 左寄せ2 | 中央寄せ2 | 右寄せ2 |
`;

console.log(parseMarkdown(markdownText));

```