# 图片替代文本中下划线的双重转义导致帖子原始内容在每次编辑时损坏

**URL:** https://meta.discourse.org/t/double-escaping-of-underscores-in-image-alt-text-corrupts-post-raw-on-each-edit/401231
**Category:** Support
**Created:** [2026年四月22日 10:42 UTC](https://meta.discourse.org/t/double-escaping-of-underscores-in-image-alt-text-corrupts-post-raw-on-each-edit/401231 "2026-04-22T10:42:21Z")
**Posts on this page:** 1
**Showing post:** 4

<div class="post-metadata">

### Author: ![zogstrip](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/zogstrip/32/512781_2.png) [@zogstrip](https://meta.discourse.org/u/zogstrip)
#### Post date: [2026年四月23日 08:41 UTC](https://meta.discourse.org/t/double-escaping-of-underscores-in-image-alt-text-corrupts-post-raw-on-each-edit/401231/4 "2026-04-23T08:41:25Z")

</div>

这个有点棘手 🤔

> <https://github.com/discourse/discourse/pull/39461>
>
> in upload filenames at generation time. That worked for freshly uploaded files b…ut exposed a latent bug in the rich-editor round-trip: markdown-it kept \`\\\_\` in the parsed image token's content, ProseMirror stored it verbatim in the \`alt\` attribute, and on save the serializer re-escaped each \`\\\` to \`\\\\\`. Every edit doubled the backslashes (1 → 2 → 4 → … → 2^N) until the post exceeded \`max\_post\_length\` and became uneditable.
> 
> \*\*Approach change\*\*
> 
> Escaping the raw is fundamentally fragile — nothing treats the stored raw as canonical, so any parse/serialize cycle either drops the escape or re-applies it. Fix it at parse time instead:
> 
> \- Revert the generation-side escaping from #39133 in \`UploadMarkdown\`, \`uploads.js\`, \`inline\_uploads.rb\`, \`to-markdown.js\`, and \`sanitizeAlt\`.
> \- Add a \`literalize\_upload\_labels\` core ruler in the markdown-it engine. After inline parsing runs, it walks \`image\` / \`link\_open\` tokens whose URL starts with \`upload://\` and collapses their children into a single literal text token. The label text is reconstructed from children \`content\` plus the \`markup\` of emphasis/strong/strikethrough delimiters, so \`\_foo\_\`, \`\*\*foo\*\*\`, \` ~~foo~~ \`, \`\` \`foo\` \`\`, \`\\\_foo\`, linkified URLs, hashtags, mentions, and emoji shortcodes inside upload labels all render literally.
> 
> The raw now stays canonical — the filename goes in verbatim, cooks the same way on every pass, and both the textarea and rich editor round-trip identically. Reference-style links
> (\`\[label\]\[ref\]\` with \`\[ref\]: upload://…\`) get the same treatment for free since they go through the same \`link\_open\`/\`image\` tokens.
> 
> \*\*Parser resilience from #39133 is kept\*\*
> 
> The multi-token scan-forward in \`renderAttachment\` (engine.js) and in ProseMirror's \`link.js\` parser still matters for non-upload attachment links like \`\[\*\*bold\*\*|attachment\](https://example.com/file.pdf)\`, where the label legitimately contains inline formatting that the new ruler doesn't touch.
> 
> \*\*Data cleanup\*\*
> 
> \`StripUploadLabelEscapes\` (post-deploy migration) heals posts already damaged by the regression with a single scoped \`regexp\_replace\`. The lookahead \`(?=\[^\\\]\]\*\\\]\\(upload://)\` bounds the match to upload labels so user-written \`\\\_\` escapes elsewhere in the raw stay intact. Excluding \`\\\` from the prefix char class keeps the greedy match from swallowing a backslash that belongs to the run being stripped.
> 
> https://meta.discourse.org/t/401231

---

_[View the full topic](https://meta.discourse.org/t/double-escaping-of-underscores-in-image-alt-text-corrupts-post-raw-on-each-edit/401231)._
