1. 先把输入这件事的边界划清楚写 Python 脚本的人九成以上都经历过这样一种尴尬本地跑得好好的程序换一个环境、换一批数据就崩了排查半天发现业务逻辑一行没错问题出在最开头那几行python3 的输入方式上。尤其是遇到多组输入这种要求看着简单真正落地时各种 EOFError、ValueError、少读一行、多读一行的问题全冒出来了。我带的几个新人里几乎每个人都要在输入处理上交一次学费才肯承认这件事值得单独拎出来研究。这篇内容不聊什么高深算法就聊输入。聊清楚三件事Python3 到底提供了哪几种读数据的手段它们各自适合什么场景以及在做多组输入的时候那些文档里不会写、但你一定会踩的坑长什么样。适合刚学完基础语法想写点实用脚本的同学也适合有一定经验、但一直在用input()一把梭、从没认真想过性能的人。看完之后你至少能做到拿到一个输入格式要求先判断该用哪种方式再动手写。1.1 输入源的三种形态在日常工作中输入这个词覆盖面比想象中宽。我把它归成三类因为这三类的处理方式完全不同混着用就是灾难的源头。第一类是交互式输入也就是程序跑起来之后人在终端里敲一行回车给一行数据。这种场景下你希望有提示语、希望用户能修改自己敲错的内容甚至希望能按方向键调出历史命令。第二类是批量数据输入程序从文件或者管道里把数据一次性吃掉可能几十万行中间没有任何人参与。第三类是参数化输入数据量很小但需要频繁变化比如命令行里传个文件名、传个日期区间。很多人出问题的根本原因是拿第一类的工具去干第二类的活。input()是个典型的交互式工具它有行编辑、有提示语、有回车等待用在批量数据上性能损耗和边界问题都会被放大。而sys.stdin家族天生就是为流式读取设计的处理起大批量数据干净利落。这两者的差别不是风格问题是量级问题后面我会用实测数字说明。1.2 为什么多组输入最容易翻车单组输入的时候格式是死的读一行、切分、转换、计算、输出写完就完事。多组输入引入了两个变量组数是否已知以及终止条件是什么。这两个变量组合起来至少有四种常见形态每种形态的循环写法都不一样一旦写错表现出来往往是答案部分正确或者最后少输出一行这种错误比直接报错还难查。我印象很深的一次某同学写了个统计脚本用来处理某批实验数据。本地测试用的样本只有 3 组跑得完美。换到完整数据集中间夹了几行空行程序在a, b map(int, input().split())这一行直接抛ValueError整批数据一条结果都没出来。他查了两个小时一直以为是数据本身有问题最后发现是没处理空行。类似这种样本内正常、样本外崩溃的情况在多组输入里太常见了。所以处理多组输入核心不是背模板而是建立起一个判断习惯先明确我读到什么时候停再明确每一组的内部结构是什么形状这两个问题答清楚了代码自然就出来了。2. input() 到底做了什么input()是绝大多数人的第一选择但真正清楚它内部干了什么的人并不多。理解它的执行过程能解释掉一大半为什么我这里会报错的疑惑。2.1 一次调用的完整生命周期当你写下line input()Python 解释器做了这么几件事先在标准输出上写出提示语如果有的话然后从标准输入读一行读到换行符为止把这个换行符去掉剩下的部分作为一个str返回。注意两个关键点返回值永远是字符串被去掉的只有行尾的换行符。第一条意味着你拿到的东西不能直接参与算术运算input() 1会直接报类型错误必须显式转换。第二条意味着行首行尾的空格、制表符都还留在字符串里只是碰巧int( 12 )能正常工作让人产生了它帮我清理过了的错觉。实际上int()本身就会忽略首尾空白是转换函数在兜底不是input()的功劳。还有个容易被忽略的细节input()在遇到输入流结束时不会返回空字符串而是直接抛EOFError。这是多组输入里最高频的异常来源。很多人的代码写成while True:然后靠读到的内容判断退出一旦输入流结束异常就冒出来了。2.2 为什么它比 readline 慢这里要说清楚一个流传很广的说法。很多人讲input()慢是因为它要处理字符串这个解释不准确——sys.stdin.readline()返回的也是字符串。真正的差别在于CPython 的input()在实现上会尝试使用行编辑功能也就是你在交互终端里按上下方向键能调出历史命令的那套机制。为此它需要逐字符读取并交给行编辑逻辑处理还涉及提示语的输出刷新。而sys.stdin.readline()直接走底层的缓冲 IO一次性把数据块读进缓冲区再从中切出一行。在数据量小的时候这个差异感知不到几十万行的时候就是几秒和零点几秒的差距。我在一台普通笔记本上做过简单对比读 50 万行纯数字input()大概要 4 秒上下sys.stdin.readline()在 1 秒出点头直接用sys.stdin.buffer.read()能压到 0.3 秒左右。这个数字随机器和 Python 版本浮动但量级关系是稳定的。所以在写需要处理大批量数据的脚本时从一开始就不该用input()。提示input()在部分运行环境里行为会变化比如被重定向到文件、或者在某些集成开发环境的内置终端里运行行编辑功能不可用此时它和readline()的差距会缩小但绝不会更快。不要指望环境来救场。2.3 提示语字符串的隐形副作用input(请输入两个数)这种写法在交互场景里很友好但在批量处理场景里是纯粹的负担。原因很简单提示语是写到标准输出上的而且不换行。如果你的程序输出会被另一段程序读取、或者会被拿去和标准答案比对多出来的提示语会直接导致结果判定失败。我见过有人为了让程序看起来友好在循环里每一轮都打印一次提示语结果输出文件里全是提示文字真正的结果被淹没。更隐蔽的一种情况是提示语和结果混在同一行因为提示语不换行后面紧跟着的print才会补一个换行导致格式完全乱掉。判断标准很直接只要是给机器读输出就不要带提示语。想要调试方便用标准错误流输出日志别碰标准输出。这个习惯养成了后面能省掉大量莫名其妙的排查时间。3. 多组输入的四种骨架写法下面这四种写法是我处理多组输入时的常用骨架覆盖了绝大部分实际会遇到的格式要求。每一种我都会说清楚它的适用前提和需要注意的边界。3.1 首行给组数 T这是最省心的一种因为组数是显式给出的循环次数确定不存在读到哪算哪的问题。骨架长这样import sys def main(): data sys.stdin first data.readline() if not first: return t int(first) out [] for _ in range(t): line data.readline() while line.strip() : line data.readline() a, b map(int, line.split()) out.append(str(a b)) sys.stdout.write(\n.join(out)) if __name__ __main__: main()里面有两个细节值得说。一是if not first: return防止输入为空的时候int()直接炸掉二是中间那个while循环跳过空行这是被数据坑过之后加上的防御。有人会问既然给了 T为什么还要防空行因为实际数据里组与组之间插空行、文件末尾多一个换行都是常有的事防御成本极低收益极高。另外我用out列表攒结果最后一次性写出。这个习惯在处理大批量输出时非常关键因为每次print都涉及一次 IO 调用和一次缓冲区刷新判断几十万次累积起来相当可观。3.2 读到文件结束为止组数不给一直读到没数据为止这是第二常见的形态。最稳的写法是直接迭代sys.stdinimport sys for line in sys.stdin: line line.strip() if not line: continue parts line.split() if len(parts) 2: continue a, b map(int, parts[:2]) print(a b)for line in sys.stdin这个写法之所以稳是因为文件对象本身是迭代器读到末尾自然停止不抛异常不需要手动捕获EOFError。相比之下while True: line input()的写法必须配try/except EOFError多一层嵌套还容易漏。这里我把len(parts)的判断也加上了。原因是有些数据文件的最后一行只有换行符或者只有半行直接解包会抛ValueError: not enough values to unpack。加一行判断把脏数据过滤掉程序就能健壮地跑完。3.3 用哨兵值收尾有些题目或者数据格式会约定读到 0 0 结束或者读到单独一个 0 结束。这种写法要注意一个点哨兵值本身不参与计算但不能在读之前就退出判断写错位置。import sys def main(): out [] for line in sys.stdin: line line.strip() if not line: continue a, b map(int, line.split()) if a 0 and b 0: break out.append(str(a b)) sys.stdout.write(\n.join(out)) main()常见的错误是把判断写在计算之后却没break或者把break写在收集结果之后导致哨兵被算进去。还有一种更隐蔽的哨兵条件用or写成if a 0 or b 0本该只在两个都为 0 时停止结果遇到第一个参数为 0 的正常数据就提前退出了。这种错误在小样本上不一定暴露因为恰好没碰到边界数据。3.4 整块读入再切分数据量大、格式又规整的时候我更喜欢一次性把整个输入读进来然后按空白切分。这种写法的好处是把 IO 次数降到最低坏处是需要自己维护一个游标代码可读性稍差。import sys def main(): tokens sys.stdin.read().split() if not tokens: return idx 0 t int(tokens[idx]); idx 1 out [] for _ in range(t): n int(tokens[idx]); idx 1 total 0 for _ in range(n): total int(tokens[idx]); idx 1 out.append(str(total)) sys.stdout.write(\n.join(out)) main()split()不带参数的时候会按任意长度的空白切分多个空格、制表符、换行符统统视为一个分隔符这正好解决了数据可能跨行也可能同行的麻烦。代价是如果数据里包含需要保留空格的字符串字段这个方法就不能用了得换回按行读。游标idx的维护是这种写法的唯一心智负担建议只在格式确定、追求速度的场景使用别在逻辑复杂的脚本里硬套。3.5 四种写法怎么选选型其实有很清晰的判断路径我整理成一张表遇到新问题对照着看就行写法适用前提性能量级主要风险input()循环交互场景、数据量小最慢提示语污染输出、EOFErrorfor line in sys.stdin组数未知、按行组织中等空行与残行需过滤read().split()数据量大、格式规整最快游标易错、不适用含空格的字段input()显式读 T 组组数明确、需要调试慢但直观后期数据量增长会拖慢选型的核心判断只有两条数据量是否可能上千行以及每一组的内部结构是否严格等长。前者决定用input()还是sys.stdin后者决定按行读还是整块读。这两条想清楚了剩下的都是细节。4. 解析环节的七个高频坑读进来了不代表解析对了。字符串切分和类型转换这一步坑的密度比读取阶段还高。4.1 split 带不带参数差别很大line.split()和line.split( )看着差不多行为完全不同。前者按任意空白切分并丢弃空字段后者严格按单个空格切分连续两个空格会产生一个空字符串元素。数据里只要出现一次连续空格或者行首缩进split( )的结果里就会冒出后面int()立刻报错。我的建议是除非你明确需要保留空字段否则一律用不带参数的split()。它能同时处理多个空格、制表符、以及行末的\r在 Windows 风格换行符残留的情况下这点尤其重要。这个问题在做跨平台数据交换时特别容易遇到同一份文件在两种系统上编辑过换行风格混在一起不带参数的split()依然能正确切分。4.2 解包数量不匹配a, b map(int, line.split())这个写法简洁但它假设了这一行恰好有两个字段。多一个少一个都会抛ValueError错误信息是too many values to unpack或not enough values to unpack指向的是解包语句跟数据哪一行有问题没直接关系排查时得自己定位。稳妥的做法是先拿到列表判断长度再取parts line.split() if len(parts) ! 2: continue a, b int(parts[0]), int(parts[1])代码多两行但出问题的时候你知道是哪一行数据不合格加个行号计数就能精确定位。另外 Python 支持星号解包first, *rest parts可以拿到第一个加其余全部处理每行第一个是数量、后面是数据这种格式很方便值得记住。4.3 空行与行末空白前面提过空行这里补一个相关的只有空格没有内容的行。line.strip() 能同时覆盖纯空行和纯空白行而line \n只能覆盖前者。用strip()判断是最省事的方案。行末空白的问题更隐蔽。从表格软件里导出的数据行末经常带一些不可见字符从网页复制的内容可能带全角空格。这类字符strip()默认能处理常见的空白但全角空格\u3000需要额外注意在某些版本的strip()行为下不会被去掉。真遇到了可以显式指定line.strip( \t\r\n\u3000)。这不是过度防御处理过真实数据的人都知道脏数据的花样永远比你想的多。4.4 类型转换的边界int()能处理前后带空白的数字也能处理正负号但遇到12.0、1e5、1,000这类字符串就直接报错。数据里出现小数是很常见的尤其是从某些统计工具导出的结果。这种时候要么用float()再转要么用Decimal保精度千万别想当然认为应该都是整数。还有个坑是大整数。Python 的int没有溢出问题多大都能算但如果你读进来之后要往某些有范围限制的地方传比如参与位运算、或者序列化成定长格式就得自己加范围校验。计算本身不会出错出错的是后续环节。map()返回的是迭代器不是列表这一点在需要多次遍历的时候要注意。list(map(int, parts))才是列表直接map对象用一次就空了第二次遍历得到空结果这种 bug 非常安静不报错但结果不对。4.5 输出端的性能与格式输入处理对了输出端还有个坑在等着。循环里print几十万次性能损耗比输入还明显。两个改法一是把结果攒进列表最后\n.join()一次性输出二是需要边算边输出的时候用sys.stdout.write()代替print。print每次调用都要处理分隔符、结束符、以及一次缓冲区写入判断虽然内部有缓冲但函数调用开销是实打实的。sys.stdout.write更接近裸写。另外注意join的用法\n.join(list_of_str)列表里必须是字符串整数要先str()转换这个转换漏掉会报TypeError而且报错位置在join那一行不在循环里容易看岔。格式方面多组输出通常要求每组一行。用join的方式天然满足但如果最后一组后面不能有多余空行就不要在末尾再补一个换行符有些严格的比对程序会因此判定格式错误。5. 大数据量下的读取优化实操前面反复提到性能这一节把实测过程完整走一遍方便你复现和验证。5.1 从 input 换成 buffer.readsys.stdin是一个文本流包装器它下面还有一层字节流通过sys.stdin.buffer访问。直接用字节流有几个好处跳过解码步骤、跳过逐行处理的逻辑、可以一次拿到全部原始数据。import sys def main(): data sys.stdin.buffer.read() nums data.split() total 0 for token in nums: total int(token) sys.stdout.write(str(total)) main()注意这里split()之后得到的是bytes对象列表int()能直接接受bytes并完成转换不需要先decode()。这个小细节很多人不知道白白多做了一次解码。当然如果数据里有中文或者其他非 ASCII 内容还是老老实实解码int()对bytes的宽容只适用于数字。5.2 输出侧同样要改输入改完输出不改收益会被吃掉一半。最简单的改法是攒列表加join再进一步可以用io.StringIO做缓冲最后一次性写出。我一般直接用列表够用且直观out [] for item in results: out.append(str(item)) sys.stdout.write(\n.join(out))还有一个容易被忽略的点是变量查找开销。在循环内部把常用的函数绑到局部变量上能省一点点write sys.stdout.write for item in results: write(str(item) \n)这种微优化在几十万次循环里能体现出来但不要为了它牺牲可读性。我的原则是先写清楚压测不过再优化优化的时候只动瓶颈那一处。5.3 一次真实压测记录我用一份 80 万行、每行两个整数的数据做过对比机器是普通的办公本Python 3.10重复三次取中间值。结果大致是这样纯input()加即时print的版本要十几秒input()读取加列表攒输出的版本降到 5 秒左右for line in sys.stdin加join输出大概 2 秒sys.stdin.buffer.read().split()全程字节处理能进 1 秒以内。差距最大的那一档接近二十倍。这组数字说明的不是你必须用最快的那种而是选错工具优化空间全被浪费了。如果数据量只有几百行随便怎么写都行纠结性能没意义。但如果你在写一个要反复跑、或者数据规模会增长的脚本从一开始就选对读取方式后面能省掉大量重构时间。判断门槛我给个经验值超过一万行就别用input()了。注意压测要在目标环境上做不同机器的磁盘、Python 版本、数据内容都会影响结果。上面的数字只用于判断量级关系不要当成绝对标准。6. 问题排查速查表与封装模板写了这么多年我发现排查输入问题的最快路径不是读代码而是看报错类型加错误信息两者组合起来基本能定位到具体环节。6.1 症状对照表报错或现象大概率原因处理方式EOFError用input()读到流末尾换for line in sys.stdin或加try/exceptValueError: invalid literal for int()字段含非数字、空字符串加strip()、过滤空行、用floatValueError: not enough values to unpack该行字段数不足先判断长度再解包ValueError: too many values to unpack该行字段数过多用切片取前 N 个或星号解包TypeError: can only join an iterable传入的不是字符串列表循环里先str()转换输出少最后一组循环条件写错哨兵提前退出检查break位置和判断条件答案部分正确空行导致错位读取跳空行加行号日志输出格式不符提示语混进 stdout去掉input()里的提示字符串这张表里我最想强调的是最后一行。很多人根本想不到输出格式不符会和input()的提示语有关因为提示语看起来像是无伤大雅的交互体验实际上它就是实打实写进标准输出的内容。一旦程序输出被拿去比对它就成了污染源。6.2 一个可复用的输入封装被坑过足够多次之后我习惯在自己的小工具里放一个输入封装把常见防御都塞进去业务代码里就不用反复写这些判断了。import sys def read_ints(): 逐行产出整数列表自动跳过空行与残行。 for line in sys.stdin: parts line.split() if not parts: continue try: yield [int(p) for p in parts] except ValueError: continue def read_pairs(): 逐行产出 (a, b)字段数不足的行直接丢弃。 for parts in read_ints(): if len(parts) 2: continue yield parts[0], parts[1]这样封装的好处是把脏数据处理策略集中到一处业务逻辑只关心我拿到的是干净的整数对。哪天数据格式变了只需要改封装不用翻遍整个脚本。另外用生成器而不是返回列表内存占用保持在 O(1)处理大文件时不会撑爆。封装的时候有个取舍要想清楚脏数据是跳过还是报错。调试阶段我倾向报错并打印行号方便定位上线跑的批量脚本里我倾向跳过并记日志保证整体能跑完。这个策略最好做成参数别写死。6.3 自测用例怎么造最后聊一个很少人提但非常实用的技巧输入处理的测试用例要专门造。正常数据谁都会测真正需要覆盖的是这几类边界空输入零字节、只有一行、最后一行没有换行符、中间夹空行、字段数不一致的行、超长行、包含制表符的行。造这些用例不需要什么工具用printf或者直接在编辑器里存几个小文本文件就够了。每种情况跑一遍确认程序要么正确处理要么优雅跳过而不是抛异常中断。我自己的习惯是在脚本旁边放一个cases目录里面按编号存这些边角输入改代码之后顺手全跑一遍比凭记忆测试可靠得多。这套流程走下来多组输入这件事其实没有太多玄学无非是把什么时候停每行长什么样脏数据怎么办这三个问题提前回答清楚。我个人在实际操作中的体会是输入处理占用的代码行数可能只有整个脚本的十分之一但它决定了这个脚本能不能在别人的机器上、在真实数据上跑起来。花半小时把这一层写扎实比事后花两小时对着一堆异常信息猜原因要划算得多。
企业数字化 ERP 产品动态
相关推荐
Libvio.link影视爬虫开发与反反爬技术实践 1. Libvio.link爬虫技术解析概述Libvio.link作为一个影视资源聚合平台,其爬虫开发涉及多个技术难点。与普通网站不同,这类平台通常采用多层次的反爬机制保护内容资源。在实际开发中,我们需要解决动态内容加载、请求频率限制、行为检测等多重技… · 2026/11/3 22:29:16
漏洞挖掘入门:从零构建Web安全攻防知识体系 1. 漏洞挖掘入门:从零开始的认知重塑第一次接触漏洞挖掘时,我盯着屏幕上那些晦涩的安全术语发愣——XSS、SQL注入、CSRF,这些名词就像天书一样。直到在某个深夜,我偶然发现一个电商网站的支付漏洞,才真正理解这个领域的… · 2026/11/3 22:29:16
Vue+Element Plus级联选择器与弹出框布局优化方案 1. 项目背景与问题定位在Vue.jsElement Plus的前端开发中,级联选择器(el-cascader)与弹出框(el-popover)的组合使用非常普遍。但当级联面板(el-cascader-panel)嵌套在弹出框中时,经常会出现布局溢出的问题——级联面板的内容超出弹出框边界,导… · 2026/11/3 22:29:16
强电磁产线接近开关误报警排查:干扰路径、抗干扰设计与选型验证 在变频驱动、伺服系统与电阻焊设备高度集中的产线上,非接触式位置检测的稳定性会直接影响节拍与良率。接近开关结构并不复杂,但输出只有通断两种状态,一次误触发就等同于向控制系统送入一条错误逻辑。本文按“问题背景—原理分析—干扰路径—… · 2026/11/4 2:30:14
AI 写的歌怎么救回来?四个隐藏功能手把手教给你 ◆ 一、读者是谁,解决什么问题如果你满足下面任意一条,这篇是写给你的: 用 AI 生成音乐做视频 BGM、播客片头、短剧配乐,量已经上来了,但成品始终「差一口气」; 生成接口调得动,交付却总要人工… · 2026/11/4 2:30:14
本地桌面客户端入门开发 1、Electron框架
官网地址:简介 | Electron
2、创建项目并安装依赖
mkdir my-electron-app
cd my-electron-app
npm init -y
npm install electron electron-builder --save-dev
3. 项目结构
my-electron-app/
├── package.json
├── main.js
└── inde… · 2026/11/4 2:30:14
程序崩了不要慌!Python 异常处理从 try-except 到自定义异常,老哥给你兜底 Python 是解释型语言,运行到哪才检查到哪。所以程序报错不丢人,怎么兜住错误让程序继续跑才是本事。Python 有两类错误:语法错误和异常。语法错误:程序解析时遇到的,如 while True print(1) 少了冒号 → SyntaxError&a… · 2026/11/4 2:30:14
SVN记录 SVN工程的IP存在修改,然后SVN up失败,如何快速修改本地文件指向的SVN工程?
当 SVN 服务器的 IP 地址发生变更后,本地工作副本仍指向旧地址,会导致 svn update 失败。要快速将本地项目重新指向新的 SVN 工程,最推荐且无损的方式是使用** Relocate(重新定位) **功能。 以… · 2026/11/4 2:29:14
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46
AI辅助技术栈评估:提升研发决策效率60% 1. 项目背景与核心价值技术决策一直是研发团队面临的重大挑战。随着技术生态的快速演进,技术栈的选择、维护和迭代变得愈发复杂。我们团队在过去两年里,先后经历了三次重大技术栈迁移,每次都需要投入大量人力进行技术评估和风险分析。直到去年… · 2026/11/4 0:00:17
从生成Token到直接决策:Jev如何重塑AI Agent工程实践 1. 从"生成文字"到"拍板决策":Jev 到底在解决什么问题大多数人第一次接触大模型,脑子里建立的模型是"输入问题、输出文字"。你问它今天天气怎么样,它给你一段描述;你让它写个周报,它给你… · 2026/11/4 0:00:17
32G统一内存跑大模型:内存账、TPS实测与端云分流 想在一台 32G 统一内存的小主机上把大模型跑成"日常可用",这件事我前后折腾了小半年。标题里说的这台 Mac mini M6,是我们这次讨论的目标平台,具体到手规格以实物为准;但下面这套推算方法和实测思路,对任何统… · 2026/11/4 0:00:17
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46