7131、6293、4762、1579:同一份稿子在四个编辑器里的四个长度
7131、6293、4762、1579同一份稿子在四个编辑器里的四个长度昨晚我发一篇稿子脚本的日志里跳出来四个数字。源文件 7131 博客园 7131 简书 6293DOM/ 8779服务端 知乎 4762 掘金 1579同一份稿子同样的读写方式四个平台读出四个长度。没有一个等于源文件的字符数——除了一个。这串数字摊在日志里特别扎眼因为它们本来是用来校验的。我写这些脚本的初衷是灌完正文之后读一下编辑器里有多少字跟源文件对不上就报警。结果四个平台里三个对不上而且差得很离谱——掘金那个差了 4.5 倍。如果我把校验条件写成编辑器长度必须等于源文件长度那三个平台会永远报警。如果我放宽到大于 500 就算成功那真的失败了我又抓不到。这篇文章就是把这四个数字拆开看清楚它们各自是怎么算出来的以及在每种编辑器里到底该拿什么当灌进去了没有的判据。一、先说结论长度根本不是一个可移植的度量四个数字之所以不同不是哪个平台算错了是因为它们测的本来就不是同一个东西。平台数字它实际在测什么博客园7131原生textarea的value.length简书DOM6293contenteditable的innerText.length简书服务端8779存进数据库的 HTML 字符串长度知乎4762渲染后文章正文innerText的长度掘金1579CodeMirror当前已渲染到 DOM 里的那部分文本五个数字五种语义。拿它们互相比较是没有意义的就像拿体重秤的读数和体温计的读数比大小。更麻烦的是同一份内容在纯文本和带标签之间本来就没有固定换算比例。markdown 源码里那些语法符号——井号、反引号、表格的竖线——渲染之后会消失而p、strong、code这些 HTML 标签又会往回加。所以服务端存 HTML → 比 markdown 源码长8779 7131渲染后的纯文本 → 比 markdown 源码短4762 7131这两个方向是反的而且偏移量取决于你这篇文章里代码块多不多、标题多不多、有没有表格。它是文章结构的函数不是常数。二、博客园唯一那个对得上的博客园的编辑器几乎是这类事情里最舒服的情况一个货真价实的textarea idmd-editor里面装的就是原始 markdown。vareldocument.querySelector(#md-editor);varrawel.value;// 原生 textarea 的全部内容console.log(raw.length);// 7131原生表单控件.value就是它的全部内容不打折不渲染不虚拟化。7131 7131一个字符都不差。为什么它能这么老实因为 markdown 编辑器不需要所见即所得——它存的就是源码预览是另一块面板的事。所见即所得才需要把 DOM 树当数据源。所以第一条经验遇到原生textarea直接用.value。它是唯一不需要任何解释的数字。顺带说一个我踩过的坑博客园这个textarea必须先真实点击聚焦再灌内容。我第一版脚本没聚焦Input.insertText直接把整篇稿子灌进了上一个聚焦元素里——那次是标题框于是标题变成了整篇正文。这个坑跟长度无关但它是同一个根因你以为你在跟编辑器对话其实你在跟浏览器的焦点管理器对话。三、简书同一个平台两个数字都对简书有意思的地方在于它给了我两个数字而两个都是真的。粘贴之后我立刻读 DOMvarareadocument.querySelector(.kalamu-area);varflatarea.innerText;// 先把 DOM 拍平成文本console.log(flat.length);// 6293然后脚本触发自动保存服务端回过来一个 JSON{id:144908349,content_updated_at:1791997831,content_size_status:fine}抓包取到服务端实际存的内容长度8779。6293 和 8779差了 2486 个字符。这不是某一方错了是它们在数不同的东西6293是浏览器把 DOM 拍平成纯文本的结果。此时 markdown 已经被引擎解析标题的#、代码块的 、加粗的**都不再作为字符存在。8779是带 HTML 标签的字符串。每个段落外面裹着p代码块裹着precode标签本身算字符。如果 DOM 里的纯文本是 6293加上标签到 8779是完全合理的。这里有一个重要的推论DOM 侧的读数不可信–服务端侧的读数才可信。因为最终存进数据库、最终会被读者看到的是服务端那一份。我在这个平台的校验逻辑现在只看两件事PUT /author/notes/id的响应码是 200响应体里content_size_status是fine。数字本身不再参与判断最多打进日志供人看。写到这里插一个跟长度无关但很痛的坑这个PUT接口要求 body 里的id是字符串并且必须带autosave_control字段。传数字 id或者漏了那个字段服务端一律回400 缺少文章内容参数—— 明明 content 好好地带在请求里。这种报错文案和真实原因完全不搭界的情形在自动化里比长度问题难缠十倍。四、知乎4762 才是文章本身的长度知乎的 4762 是我换了一个读法得到的。这个平台我是这么做的先在写文章页用 Draft.js 的resetWithValue()把 HTML 灌进去然后点发布最后另开一个标签打开文章页读vareldocument.querySelector(.RichText);varshownel.innerText;console.log(shown.length);// 4762注意这一步的位置它不是在编辑器里读的是在发布之后的成品页上读的。这两个位置差别巨大。在编辑器里读你读到的是编辑器此刻的内部状态在成品页读你读到的是服务端存量 前端渲染结果的合取。前者可能发生前端看着有了、服务端没存的问题简书这类contenteditable编辑器就经常如此——用document.execCommand(insertText)灌进去的文本React 不认编辑器的自动保存会拿空状态覆盖掉你在 DOM 里看到的内容。所以 4762 这个数字虽然跟源文件差了近 2400却是我最愿意相信的一个——它是终点不是中途站。这也是我在上一篇文章里讲过的判据分级弱判据 页面上写着什么中判据 DOM 状态 / 接口响应强判据 结果的对外可见状态另开一个标签用读者的身份去看这篇文章在不在、多少字——这是最贵的一种校验多一次导航、多一次等待也是唯一不会被自欺的一种。五、掘金1579 是最有意思的那个最后说掘金因为它最反直觉。CM_LEN 1625 CM_LEN 1577 CM_LEN 1579 CM_LEN 1625这是我隔几分钟跑了几次读到的值。同一篇稿子同一个页面四次读数都不一样。原因掘金的编辑器是 CodeMirror而 CodeMirror 用的是虚拟滚动。一篇 7131 字符、300 多行的文章它只把当前视口里那十几二十行真正渲染成 DOM 节点其余的在滚动条出现时才生成。所以innerText读到的永远只是此刻屏幕上可见的那一小截。往下滚一点读数变大往上滚读数变小。我那四次读数的差异就是滚动位置不同造成的。这意味着什么如果你在一个 CodeMirror 编辑器上用innerText.length做校验你得到的不是一个数是一个跟滚动位置相关的随机变量。它有下界至少要能填满一屏没有稳定的上界。我当时写的判据是cmLen 500就算灌入失败。这个阈值侥幸生效了——1579 500脚本判断灌进去了。但如果那天我发的文章短一些呢或者某次它正好滚到顶部只渲染了 400 字呢这个判据会在毫无征兆的情况下误报而我不会知道。正确做法有两种// 一直接问编辑器实例绕过 DOMvarcmdocument.querySelector(.CodeMirror).CodeMirror;console.log(cm.getValue().length);// 二退而求其次读行数console.log(document.querySelectorAll(.CodeMirror-line).length);第一种最好——CodeMirror 实例挂了CodeMirror属性在容器上getValue()拿的是完整文档对象跟渲染无关。顺带这个属性名跟库同名第一次看到容易以为是个 bug。六、跳出长度什么才是可移植的判据四个平台走完你会发现长度这个度量从一开始就选错了。它便宜、直观、写代码的时候顺手但它测的东西在不同平台上语义不一致而且会受到渲染模型、虚拟滚动、标记语言的共同扰动。我现在用的替代品是一个笨办法校验特征串而不是校验数量。// 源文件最后一行的前 24 个字符varMARK判断一件事成没成永远去看它对外部世界造成了什么改变;// 灌完之后在目标元素里找这个串varseentargetEl.innerText;varokseen.includes(MARK);它好在几个地方第一它对渲染掉了什么免疫。markdown 符号被解析没了没关系我要找的是正文本身的一段话它在任何渲染模型里都会保留。第二它对虚拟滚动免疫。CodeMirror 只渲染了视口内的行那我就滚到底部或者干脆用getValue()。只要那一句话在就说明整篇稿子灌进去了——因为它是最后一段。第三它能发现灌了一半。这是长度校验做不到的。假设粘贴在中途断了前 3000 字进去了后 4000 字丢了——长度读数是 3000如果你的阈值是 500你会判定成功。而特征串选在结尾找不到就是没灌完一个字都不会漏。第四它跟平台的存盘格式无关。不管对方存 markdown、存 HTML 还是存 Draft.js 的 block 树那段中文的形式都一样。代价只有一个它不能告诉你灌了多少。它能回答的是一个是非题不是一道算术题。但说实话在发布流水线里我需要回答的本来就是是非题。“这篇稿子完整地进去了吗”——是或否。至于进去之后是 6293 还是 8779那是排版的事不是我该在这一步关心的事。七、一份对照表最后留个速查表下次写新平台的脚本可以照着填。编辑器类型别这么读该这么读代表平台原生textarea—取value再取length博客园CodeMirrorinnerText.length虚拟滚动cm.getValue().length掘金Draft.js编辑器里的 DOM发布后另开标签读成品页知乎contenteditable ReactDOM execCommand灌入服务端响应体 TA 的 content 长度简书Cherry Markdowntextarea的 setValue分块逐行键入后读行数腾讯云以及一条铁律能用服务端回声就别用本地测量。服务端回的那个数是它真的存下来的东西本地测量的数是浏览器此刻展示的东西。这两者之间隔着一整套框架状态同步随时可能不同步。本文所有数字均来自 2026-10-15 一次真实的四平台发文日志源文件 7131 字符。

相关新闻

Java 转 Python 后端 04: GIL 机制、单线程事件循环与异步并发实战

Java 转 Python 后端 04: GIL 机制、单线程事件循环与异步并发实战

第 5 章 并发体系、异步编程与 Agent 后端实战 5.1 并发基石:GIL 机制与并发选型矩阵 Java 工程师非常熟悉 JVM 内存模型(JMM)、内核线程与 JUC 线程池,在 Java 里多线程可以轻松打满多核 CPU。而在 Python 中,首先需要…

2026/10/17 6:55:01 阅读更多 →
Python集成学习实战:从Bagging手写到LightGBM时序CV与Stacking元特征

Python集成学习实战:从Bagging手写到LightGBM时序CV与Stacking元特征

简介:这是一本面向Python开发者与机器学习实践者的集成学习速成指南,适合已掌握基础Python、NumPy及scikit-learn的中初级学习者,旨在7天内系统掌握装袋、随机森林、AdaBoost、梯度提升、投票与堆叠六大主流集成方法,解决单一模型…

2026/10/17 6:55:01 阅读更多 →
Harbor私有镜像仓库部署与运维实践:从架构到避坑指南

Harbor私有镜像仓库部署与运维实践:从架构到避坑指南

一套业务系统跑了一两年,环境中几十上百个容器,镜像分散在各台机器甚至每个人电脑里,等到要统一发版、回滚版本的时候,才发现连一个准确的镜像清单都凑不出来。这种场景我想很多团队都经历过。所以当我的某位合作伙伴第一次提出“…

2026/10/17 6:54:01 阅读更多 →

最新新闻

Node.js工程化实战:从开发热更到生产部署的6大核心工具链解析

Node.js工程化实战:从开发热更到生产部署的6大核心工具链解析

1. 这不是工具清单,而是一张Node.js工程化生存地图你刚写完一个Express接口,本地node app.js能跑通,但改一行代码就得手动CtrlC再回车;你听说nodemon能热更新,装上后却卡在“watching 1234 files”不动;项目…

2026/10/17 7:37:11 阅读更多 →
Node.js 工程化实战:从本地开发到生产部署的六大核心链路

Node.js 工程化实战:从本地开发到生产部署的六大核心链路

1. 这不是工具清单,而是一套 Node.js 工程师的日常生存手册 你有没有过这样的时刻:刚 clone 下来一个项目, npm install 卡在 node-gyp rebuild 上一动不动,终端里全是红字;改完一行代码想看效果,得手…

2026/10/17 7:37:11 阅读更多 →
SITC实践指南(共识一):多重免疫组化有多种,不止TSA-mIHC

SITC实践指南(共识一):多重免疫组化有多种,不止TSA-mIHC

肿瘤微环境(TME)中免疫细胞的组成、功能蛋白的表达模式、基质细胞的空间分布,与疾病预后和免疫治疗响应关系紧密。比如肿瘤细胞和免疫细胞的PD-L1表达水平、治疗前肿瘤标本中存在的CD8 T细胞浸润密度,均与免疫检查点抑制剂治疗效果…

2026/10/17 7:37:11 阅读更多 →
MatIEC Stage4源码解析:从AST到C代码的PLC编译器后端实现

MatIEC Stage4源码解析:从AST到C代码的PLC编译器后端实现

MatIEC 这个开源项目,估计玩 PLC 上位机开发或者做工业编译器的人多少都有印象。它比那些只能出汇编的教学编译器务实得多,整个架构直接照搬了经典的多阶段编译流程,词法、语法、语义一层层剥下去,最后在 Stage4 这个模块里把抽象…

2026/10/17 7:37:11 阅读更多 →
8GB内存无GPU笔记本部署Llama2多模态模型实现离线图片识别全攻略

8GB内存无GPU笔记本部署Llama2多模态模型实现离线图片识别全攻略

"8GB内存的办公笔记本,集成显卡,还想跑大模型?跑完还想让它识别图片内容?"——这是我最近被问到最多的问题,也是我花了一周时间完整走通的一条路。坦白讲,以前我也觉得大模型是显卡发烧友的玩具&…

2026/10/17 7:37:11 阅读更多 →
激光雷达+Unity3D:互动投影捕鱼游戏完整实现方案

激光雷达+Unity3D:互动投影捕鱼游戏完整实现方案

简介:这是一份面向互动投影开发者的Unity3D捕鱼游戏案例包,基于激光雷达技术实现肢体交互,画面清晰流畅,适合在商场、展馆、游乐场等互动场景中进行功能演示与效果测试。压缩包体量约26.64MB,整体轻量便捷,…

2026/10/17 7:36:11 阅读更多 →

日新闻

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

简介:《DeepSeek使用方法.pdf》是一份面向DeepSeek入门及进阶用户的完整使用指南,重点围绕V3与R1两款模型的能力差异与适用场景展开,帮助读者根据任务类型与成本选择合适的模型。资源共1个PDF文件,压缩包大小约311KB,篇…

2026/10/17 0:00:25 阅读更多 →
200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

简介:这是一份聚焦DeepSeek提示词优化的《200Deepseek润色指令》PDF文档,共收录两百余条可直接套用的润色指令,涵盖语法修正、风格统一、逻辑梳理、表达精炼等维度,并针对商务写作、学术论文、广告文案等场景给出差异化建议。文档…

2026/10/17 0:00:25 阅读更多 →
OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

简介:本资源是一份基于OpenCV的本科课程设计完整报告,面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生,解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓检测、边界框绘制、轨迹栏交互式参数调节、…

2026/10/17 0:00:25 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/16 21:35:51 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/17 1:44:59 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 21:54:38 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →