マークダウンでのエスケープの修正
守矢諏訪子 <suwako@076.moe>、2026-04-24 19:53
コミット 7492790a9cd32ec1c2a38724567bfc6cecb1aef1
・親 119f9f4
・ファイルを見る
1個のファイル、+17 -15
| @@ -275,39 +275,39 @@ | ||
| 275 | 275 | |
| 276 | 276 | $patterns = [ |
| 277 | 277 | // 数式 |
| 278 | - '/\$\$([^$]+)\$\$/u' => function($matches): string { | |
| 278 | + '/(?<!\\\\)\$\$([^$]+)\$\$/u' => function($matches): string { | |
| 279 | 279 | $placeholder = "{{ALG".count($this->algebraicPlaceholder).'ALG}}'; |
| 280 | 280 | $this->algebraicPlaceholder[$placeholder] = $matches[1]; |
| 281 | 281 | return $placeholder; |
| 282 | 282 | }, |
| 283 | 283 | // 太字 |
| 284 | - '/\*\*(.+?)\*\*/u' => '<strong>$1</strong>', | |
| 284 | + '/(?<!\\\\)\*\*(.+?)\*\*/u' => '<strong>$1</strong>', | |
| 285 | 285 | // 斜体 |
| 286 | - '/\*(.+?)\*/u' => '<em>$1</em>', | |
| 286 | + '/(?<!\\\\)\*(.+?)\*/u' => '<em>$1</em>', | |
| 287 | 287 | // 下線 |
| 288 | - '/\_(.+?)\_/u' => '<u>$1</u>', | |
| 288 | + '/(?<!\\\\)_(.+?)_/u' => '<u>$1</u>', | |
| 289 | 289 | // 取り消し線 |
| 290 | - '/\~(.+?)\~/u' => '<s>$1</s>', | |
| 290 | + '/(?<!\\\\)~(.+?)~/u' => '<s>$1</s>', | |
| 291 | 291 | // Blink (with speed) |
| 292 | - '/!:\((.+?)\)(.+?):!/u' => '<span class="blink" style="animation-duration: $1s;">$2</span>', | |
| 292 | + '/(?<!\\\\)!:\((.+?)\)(.+?):!/u' => '<span class="blink" style="animation-duration: $1s;">$2</span>', | |
| 293 | 293 | // Blink |
| 294 | - '/!:(.+?):!/u' => '<span class="blink">$1</span>', | |
| 294 | + '/(?<!\\\\)!:(.+?):!/u' => '<span class="blink">$1</span>', | |
| 295 | 295 | // フォントの大きさ |
| 296 | - '/\^\((.+?)\)(.+?)\^/u' => '<span style="font-size: $1px;">$2</span>', | |
| 296 | + '/(?<!\\\\)\^\((.+?)\)(.+?)\^/u' => '<span style="font-size: $1px;">$2</span>', | |
| 297 | 297 | // フォントカラー |
| 298 | - '/\%\((.+?)\)(.+?)\%/u' => '<span style="color: #$1;">$2</span>', | |
| 298 | + '/(?<!\\\\)\%\((.+?)\)(.+?)\%/u' => '<span style="color: #$1;">$2</span>', | |
| 299 | 299 | // 画像 |
| 300 | - '/\!\[(.*?)(?:#([^\]]*))?\]\((.+?)\)/u' => '<img style="width: 100%; $2" src="$3" alt="$1" />', | |
| 300 | + '/(?<!\\\\)\!\[(.*?)(?:#([^\]]*))?\]\((.+?)\)/u' => '<img style="width: 100%; $2" src="$3" alt="$1" />', | |
| 301 | 301 | // 音楽 |
| 302 | - '/\$\[([^\]]+)\]\(([^\)]+)\)/u' => '<audio controls><source src="$2" type="$1" /></audio>', | |
| 302 | + '/(?<!\\\\)\$\[([^\]]+)\]\(([^\)]+)\)/u' => '<audio controls><source src="$2" type="$1" /></audio>', | |
| 303 | 303 | // 動画 |
| 304 | - '/\#\[([^\]]+)\]\(([^\)]+)\)/u' => '<video style="max-width: 100%;" controls><source src="$2" type="$1" /></video>', | |
| 304 | + '/(?<!\\\\)\#\[([^\]]+)\]\(([^\)]+)\)/u' => '<video style="max-width: 100%;" controls><source src="$2" type="$1" /></video>', | |
| 305 | 305 | // リンク |
| 306 | - '/\[(.+?)\]\((.+?)\)/u' => '<a href="$2">$1</a>', | |
| 306 | + '/(?<!\\\\)\[(.+?)\]\((.+?)\)/u' => '<a href="$2">$1</a>', | |
| 307 | 307 | // 振り仮名 |
| 308 | - '/\<(.+?)\>\((.+?)\)/u' => '<ruby>$1<rp>(</rp><rt>$2</rt><rp>)</rp></ruby>', | |
| 308 | + '/(?<!\\\\)<(.+?)>\((.+?)\)/u' => '<ruby>$1<rp>(</rp><rt>$2</rt><rp>)</rp></ruby>', | |
| 309 | 309 | // インラインコード |
| 310 | - '/`(.+?)`/u' => '<code>$1</code>', | |
| 310 | + '/(?<!\\\\)`(.+?)`/u' => '<code>$1</code>', | |
| 311 | 311 | ]; |
| 312 | 312 | |
| 313 | 313 | foreach ($patterns as $pattern => $replacement) { |
| @@ -324,6 +324,8 @@ | ||
| 324 | 324 | foreach ($this->algebraicPlaceholder as $placeholder => $expr) { |
| 325 | 325 | $text = str_replace($placeholder, $this->parseAlgebraic($expr), $text); |
| 326 | 326 | } |
| 327 | + | |
| 328 | + $text = preg_replace('/\\\\(.)/u', '$1', $text); | |
| 327 | 329 | |
| 328 | 330 | return $text; |
| 329 | 331 | } |