制表符转空格转换器

把文本里的制表符按制表位(tab stop)展开成空格:遇到制表符时补足到下一个制表位的整数倍,不是一律换成固定数量的空格。宽度 1 到 16 可调,默认 4;逐行给出制表位数与补空格数,三种换行格式全认,行首缩进不丢。

常用档位:4 = 主流编辑器默认;8 = Unix 传统(expand 默认值)。本页只做「制表符 → 空格」单向转换。
反向(空格折回制表符)不总是可逆,本页不做,原因见正文「计算原理与变量说明」。
按制表位展开:每个制表符补「宽度 − (列号 mod 宽度)」个空格,每行从列 0 重新起算;三种换行(LF、CRLF、CR)都按行拆分,行首制表符同样展开。列号按显示宽度计:中日韩字符记 2 列,其余记 1 列。
制表位宽度 4 | 5 行 | 制表符 6 个 | 补空格 18 个
-- 转换后全文 --
a   b
abc d
abcd    e
12345678    X
a   b   c
处理行数5 行
制表符6 个
补空格18 个
制表位宽度4 列
行号原文(→ 代表制表符)制表位数补空格数转换后
1a→b13a b
2abc→d11abc d
3abcd→e14abcd e
412345678→X1412345678 X
5a→b→c26a b c

默认示例:宽度 4、5 行含 6 个制表符。改宽度或按回车立即重算;输入框按 Ctrl+Enter(Mac 上 Cmd+Enter)转换。明细表默认显示 12 行,点「加载更多」展开全部。

使用方法

  1. 「制表位宽度」默认 4,允许 1 到 16 的整数;改数字或按回车立即重算。
  2. 「输入内容」粘贴或输入含制表符的文本,默认示例 5 行、6 个制表符。输入框按 Ctrl+Enter(Mac 上 Cmd+Enter)触发转换。
  3. 结果区首行给出宽度、行数、制表符总数与补空格总数;「转换后全文」是可直接复制使用的成品文本。
  4. 逐行对照表给出每行的原文(制表符显示为 →)、制表位数、补空格数与转换结果,用来核对每一行补了多少。
  5. 明细表默认显示 12 行,点「加载更多」展开全部;「导出 CSV」存成带字节序标记的文件,Excel 打开不乱码。
  6. 「复制结果」复制转换后的全文;「复制对照表」把当前明细表按 TSV 复制,粘进表格软件列位不乱。
  7. 宽度只影响补多少个空格,不改变字符顺序;同一份输入,宽度 4 与宽度 8 的结果行数、制表符数完全相同,只有空格数不同。
  8. 宽度写成 0 或 17、输入留空,都会给出针对该项的具体提示,不会拿上一次的结果冒充本次输出。

这个制表符转空格转换器能解决什么问题

第一类是「粘贴进来对不齐」。从终端日志、老旧代码或别人的配置里复制出来的文本,制表符在不同软件里渲染宽度不同,粘到别处就歪。本页把制表符按制表位展开成真实空格,宽度自己定,粘到哪儿都是同一副样子。

第二类是「一律替换踩坑」。很多人以为 Tab 转空格就是把每个制表符换成 4 个空格,结果第二列起全部错位:ab 后面本该补 2 个空格对齐到第 4 列,一律替换给了 4 个,直接冲到第 6 列。本页按「下一个制表位的整数倍」补,ab 后面就是 2 个空格。

第三类是 Makefile 与构建脚本的坑。Makefile 的 recipe 行必须以制表符开头,换成空格会报 missing separator;把含制表符的构建片段贴进网页、文档或 issue 时,同样会因宽度差异被读错。本页先把制表符显式展开,再粘贴到不支持制表位的载体上。

第四类是缩进审计。团队规范要求纯空格缩进,但要先知道每行有几个制表符、展开后补了几个空格。对照表的「制表位数」与「补空格数」两列就是审计依据:默认第 5 行有两个制表符、补 6 个空格,一眼可查。

这个工具在本站也叫「制表符转空格转换器」,只做制表符到空格一个方向;反向(空格折回制表符)不是总能可逆,本页有意不做,原因写在正文。

计算原理与变量说明

核心规则只有一行。按制表位(tab stop)展开:设宽度为 w,遇到制表符时补 w − (列号 mod w) 个空格,让当前列落到下一个制表位的整数倍上。列号从 0 开始计:字符 a 占第 0 列,打到 a 后列号变 1;在列号 1 处遇制表符且 w = 4,补 4 − (1 mod 4) = 3 个空格。如果列号恰好是 w 的整数倍,就补满 w 个——abcd 后面那个制表符正是如此,补 4 个空格。

精核过的例子(w = 4)。a→b 得 a···b(补 3);ab→c 得 ab··c(补 2);abc→d 得 abc·d(补 1);abcd→e 得 abcd····e(补 4);a→b→c 得 a···b···c(两个制表符各补 3);12345678→X 得 12345678····X(8 列已是制表位,补 4)。若把宽度改成 8,行首的 →x 补满 8 个空格。这里的 · 只代表一个空格,输出里都是真空格。

为什么不能一律替换。把每个制表符都换成固定 N 个空格,第一列也许碰巧对齐,第二列起必然错位——因为「补几个空格」取决于制表符落在第几列,而列号由前面的字符决定。这正是 Makefile 里 Tab 不能被空格替代的同一回事:Make 认的是「行首是制表符」这个语法事实,不是视觉宽度,换成等量空格直接报 missing separator。

每行从列 0 重新起算。制表位不跨行累计:第 1 行结束时的列号不影响第 2 行,每行都从第 0 列开始数。换行支持 LF、CRLF、CR 三种,按行拆分后各自展开;行首的制表符同样按规则补空格,缩进场景(代码块、层级列表)的层级不会被抹平。

宽度为什么默认 4。4 是主流编辑器的常见档位(VS Code 等默认 tab size 即 4);传统 Unix 工具链常用 8——expand 的默认制表位就是 8,Linux 内核代码风格也用 8。两种都对,只是口径不同,所以本页把宽度做成显式输入项,1 到 16 可调,不替用户猜。

列号按显示宽度计。中日韩字符、全角标点记 2 列,其余记 1 列,与等宽终端的口径一致;代理对(emoji 等)按两个码元各 1 列计。这个口径影响的是补几个空格,不影响任何已有字符。

反向不做。空格折回制表符只有当成组空格恰好对齐到制表位时才无损;把「任意」空格折回去会改变内容语义(比如对齐用的空格与缩进用的空格混在一起时无法区分)。本页只做制表符到空格这一个方向,并在结果区注明。

完整示例(数值仅作演示)

默认示例:宽度 4,输入 5 行、6 个制表符。转换后全文逐字如下——第 1 行 a b(a 后 3 个空格);第 2 行 abc d(1 个空格);第 3 行 abcd e(4 个空格);第 4 行 12345678 X(4 个空格);第 5 行 a b c(两个制表符各补 3 个,共 6 个)。合计补空格 3+1+4+4+6 = 18 个,与结果区首行一致。

逐行对照表把这 5 行摊开:第 1 行原文 a→b、制表位 1 个、补 3 个空格;第 5 行原文 a→b→c、制表位 2 个、补 6 个空格。任一行补的数 = 该行每个制表符各自的 w − (列号 mod w) 之和。

换宽度看差异。宽度改成 8,第 1 行变成 a b(补 7 个空格,落到第 8 列),第 4 行因为 8 列正好是制表位仍然补 8 个;宽度改成 2,第 1 行补 1 个空格(1 mod 2 = 1,补 2−1 = 1),第 4 行 12345678 是 8 个字符、8 mod 2 = 0,补满 2 个。

精核例子与「一律替换」错位对照表

下表左两列是精核过的输入与补空格数(宽度 4,最后一行为宽度 8),右列是输出,· 代表一个空格。→ 代表输入里的一个制表符。

输入(→ = 制表符)宽度补空格数输出(· = 空格)
a→b43a···b
ab→c42ab··c
abc→d41abc·d
abcd→e44abcd····e
a→b→c43 + 3a···b···c
12345678→X4412345678····X
→x88········x

下表把「一律换成 4 个空格」与「按制表位展开」摆在一起:第一行碰巧看着接近,第二行起一律替换就整体跑偏,错位的列数随每行前缀长度变化。

输入(→ = 制表符)一律换成 4 个空格(错)按制表位展开(对)
a→ba····ba···b
ab→cab····cab··c
abc→dabc····dabc·d
a→b→ca····b····ca···b···c

结果边界与舍入说明

常见问题

为什么不能把每个制表符都换成 4 个空格?

因为该补几个空格取决于制表符落在第几列,而列号由同一行里它前面的字符决定。规则是补「宽度 − (列号 mod 宽度)」个空格:a 后面补 3 个、ab 后面补 2 个、abc 后面补 1 个、abcd 后面补 4 个。一律换成 4 个,第一行也许碰巧对齐,第二列起必然错位。

这和 Makefile 报 missing separator 是一回事吗?

是同一类问题的两个面。Make 要求 recipe 行首是制表符这个语法事实,换成等量空格就报 missing separator;本页处理的是视觉层:把制表符展开成与制表位对齐的空格,让文本在只认空格的载体(网页、文档、issue)上不错位。注意展开后的文本反过来不能再喂给 Make。

宽度选 4 还是 8?

看目标场景。4 是主流编辑器的常见档位(VS Code 等默认值);8 是传统 Unix 工具链的口径(expand 默认制表位为 8,Linux 内核代码风格也用 8)。本页默认 4,并把宽度做成 1 到 16 的显式输入项,不替用户猜。

每行都从第 0 列重新数制表位吗?跨行会累计吗?

不累计,每行独立从列 0 开始。第 1 行结束时停在第几列,不影响第 2 行的第一个制表符补几个空格。换行按 LF、CRLF、CR 三种格式拆分,各自展开。

行首的制表符(缩进)会被处理吗?

会,而且必须处理。行首制表符同样按「补到下一个制表位」展开,代码块与层级列表的缩进层级不会丢。默认示例没有行首制表符,粘一段带缩进的代码进去就能在对照表里看到每行的补空格数。

为什么没有「空格转制表符」的反向功能?

因为它不总是可逆。把成组空格折回制表符,只有在这组空格恰好从某个制表位开始、到下一个制表位结束时才无损;对齐用的空格和缩进用的空格混在一起时根本无法区分。本页只做制表符到空格一个方向,并在工具区标明。

中文按几列算?会不会和终端显示不一致?

本页按显示宽度计:中日韩字符与全角标点记 2 列,其余记 1 列,与等宽终端口径一致;emoji 等代理对按两个码元各 1 列计。这个口径只影响补几个空格,输出里所有原有字符一个不少。

输入的数据会上传吗?工具免费吗?

免费,无需注册。所有转换都在当前浏览器本地完成,页面不联网、不写 localStorage,输入内容只用于本次转换。

相关工具