缩进转换
Tab↔Space/自定义宽度
缩进风格指南
· Tab:Go / Linux Kernel / Makefile 强制 / 部分 JS / Python(PEP 8 旧版允许)
· 4 空格:Python(PEP 8 推荐) / Java / Rust / Swift / 多数现代语言
· 2 空格:JS / TS / Ruby / YAML / HTML / CSS / Vue / React
· .editorconfig:项目根目录放此文件,让所有编辑器自动应用统一缩进
· 混合警告:同一文件 Tab 和 Spaces 混用是常见 bug 源(特别 Python 3 直接报错)
关于本工具
了解工具定位 · 使用场景 · 对比优势
将代码或文本中的 Tab 与 Space 互相转换,并支持自定义缩进宽度(2/4/8 格等)。前端开发者统一团队代码风格、运维人员修复配置文件缩进错误、写 YAML/JSON 时对齐格式,粘贴即转。所有处理在浏览器本地完成,内容不上传服务器。
使用场景
团队代码规范
多人协作的 Python 项目,有人用 4 空格缩进,有人用 Tab。每次合并代码都会出现缩进混乱的 diff,review 时浪费大量时间在格式纠错上。用本工具一键将整个目录的 .py 文件统一为 4 空格缩进,确保所有人的提交风格一致,让 code review 聚焦在逻辑而非格式。
YAML 配置编写
Kubernetes 或 Docker Compose 的 YAML 文件严格依赖缩进层级,一个 Tab 混入空格就可能导致解析失败。在编写或从文档复制配置时,用本工具将缩进统一为 2 空格,并自定义宽度以对齐嵌套层级,避免因缩进错误导致的部署报错。
跨项目代码迁移
从使用 Tab 缩进的旧项目迁移代码到使用 4 空格缩进的新项目,手动替换每个文件既慢又容易漏改。使用本工具批量将 Tab 转换为 4 空格,保留代码逻辑结构不变,迁移后直接通过 lint 检查,无需二次调整。
Markdown 文档排版
从不同来源拼接的 Markdown 文档(如 GitHub Wiki 和本地笔记)缩进风格不统一,导致列表嵌套层级错乱。用本工具将文档中的所有缩进统一为 2 空格,修复列表和代码块的层级显示,让文档在渲染后结构清晰、可读性提升。
Makefile 维护
Makefile 中 Tab 是语法要求,不能替换为空格。从网上复制 Makefile 片段时,如果缩进被自动转为空格,执行 make 会报“分隔符缺失”错误。用本工具将空格还原为 Tab,确保 Makefile 语法正确,避免因缩进问题导致构建失败。
对比矩阵本工具 vs 竞品 vs 传统方法
| 维度 | 本工具 | 竞品 A(Code Beautify) | 传统方法(IDE 替换功能) |
|---|---|---|---|
| 数据隐私 | 纯浏览器,零上传 | 上传到服务器处理 | 本地文件操作,无上传 |
| 处理速度 | 即时(毫秒级) | 需等待网络往返(1-3 秒) | 取决于 IDE 启动和操作步骤(数秒至分钟) |
| 离线可用 | 完全离线(FE 实现) | 需联网 | 完全离线 |
| 批量处理 | 一次一段文本 | 一次一段文本 | 可批量替换整个项目文件 |
| 自定义宽度 | 支持任意整数(1-8) | 仅支持 2/4/8 预设 | 支持任意整数(需手动配置) |
| 操作步骤 | 粘贴 → 点击 → 复制 | 粘贴 → 选择 → 点击 → 复制 | 打开 IDE → 选中 → 替换对话框 → 配置 → 执行 |
| 平台依赖 | 任何浏览器 | 任何浏览器 | 需安装特定 IDE(如 VS Code) |
| 收费 | 免费 | 免费(有广告) | IDE 本身可能收费 |
使用指南
上手步骤 · 输入输出 · 避坑提示
使用步骤
- 在输入框中粘贴或直接键入代码文本,支持 Tab 和 Space 混合内容
- 选择转换方向:Tab→Space 或 Space→Tab,也可自定义空格宽度(2/4/8)
- 点击「转换」按钮,结果区即时显示转换后的代码文本
- 点击「复制」按钮将结果复制到剪贴板,或手动选中文本复制
输入输出示例7 个典型场景,覆盖常规、边界与易错
| 输入 | 输出 | 说明 |
|---|---|---|
| return 0; | return 0; | 典型场景:4 空格缩进转换为 1 个 Tab |
| function foo() { console.log(1); } | function foo() { console.log(1); } | 常见用法:多行代码统一从 8 空格转为 Tab |
| x = 1; | x = 1; | 边界 case:连续 12 个 Tab 转为等宽空格,不截断 |
| mixed; | mixed; | 易错 case:Tab 和空格混排时,逐个字符转换 |
| 边界 case:空输入直接返回空,不报错 | ||
| a b c | a b c | 典型场景:每行缩进量不同,分别独立转换 |
| 边界 case:仅含空格的空行,保持原样 |
常见错误对照7 个常踩的坑 · 错误 → 修复
1. 混用 Tab 和 Space 后直接转换
代码里既有 Tab 又有 4 空格缩进,直接点击「Tab→Space」先统一所有缩进为 Tab 或 Space,再执行转换。或使用工具的「智能合并」模式(如存在)混用缩进时,工具会按当前光标位置或首行缩进类型处理,导致部分行缩进量计算错误,破坏对齐
2. 自定义宽度与已有缩进不匹配
原代码用 2 空格缩进,设置「Tab 宽度=4」后转成 Tab先确认原缩进宽度(如 2 空格),将 Tab 宽度设为 2 再转换,或直接转为 2 空格Tab 在视觉上可代表任意宽度,但转换时工具按「1 Tab = N 空格」的固定规则计算;宽度设错会导致缩进量翻倍或减半
3. 把缩进转换当成格式化工具
用缩进转换工具处理一段没有缩进、换行混乱的代码先用代码格式化工具(如 Prettier/ESLint --fix)整理结构,再用缩进转换统一缩进风格缩进转换只改变缩进字符(Tab↔Space)和缩进量,不处理换行、括号对齐、多余空格等格式化问题
4. 转换后缩进量变成非整数
原代码 3 空格缩进,Tab 宽度设为 2,转换后得到 1.5 个 Tab「Tab→Space」时设置目标宽度为原宽度的整数倍,或「Space→Tab」时确保原空格数是 Tab 宽度的整数倍Tab 必须是整数个,非整数倍的空格会被保留为多余空格,导致缩进不齐。例如 3 空格转 2 空格 Tab 会变成「1 Tab + 1 空格」
5. 忽略 YAML 对 Tab 的严格禁止
在 YAML 文件中使用 Tab 缩进后,用工具转成 SpaceYAML 文件应始终使用空格缩进(通常 2 空格),转换时确保所有 Tab 被替换为对应数量的空格YAML 规范(yaml.org/spec/1.2)明确禁止 Tab 作为缩进字符,即使视觉上对齐,YAML 解析器也会报错
6. 对 Makefile 使用 Space 缩进
在 Makefile 的 recipe 行使用空格缩进,然后试图用工具转为 TabMakefile 中 recipe 行必须使用 Tab 缩进,直接保留 Tab 或从 Space 转为 TabGNU Make 要求 recipe 行以 Tab 开头,空格会被视为普通字符导致「missing separator」错误
7. 转换后忘记检查字符串内的缩进
代码中多行字符串(如 Python 三重引号)包含缩进,转换后字符串内容被改变转换前确认工具是否支持「忽略字符串/注释」选项;若无,手动检查并恢复字符串内的原始缩进缩进转换通常对整段文本全局操作,不会区分代码和字符串字面量,可能导致字符串内容意外变化
工作原理
公式推导 · 流程图解 · 依据出处
核心公式
N = L × (T / S)
变量说明
N— 转换后的缩进字符数L— 原始缩进字符数T— 原始缩进类型(Tab=1, Space=1)S— 目标缩进宽度(空格数)
示例
将 4 个 Tab 缩进转换为 2 空格缩进:L=4, T=1(Tab), S=2。N = 4 × (1 / 2) = 2。结果:4 个 Tab 变为 2 个空格。
适用范围
适用于纯文本文件中 Tab↔Space 的等宽转换。不适用于混合缩进(Tab+Space 混排)或非等宽字体环境。基于 ASCII 标准缩进约定。
原理图
开发者集成
3 种主流语言 · 复制即用
import re
def convert_indent(text: str, from_tab: bool, tab_width: int = 4) -> str:
"""
Convert between tabs and spaces.
from_tab=True: tab → spaces; from_tab=False: spaces → tab
"""
if from_tab:
# Replace each tab with given number of spaces
return text.replace('\t', ' ' * tab_width)
else:
# Replace leading spaces (multiples of tab_width) with tabs
lines = text.split('\n')
result = []
for line in lines:
stripped = line.lstrip(' ')
leading_spaces = len(line) - len(stripped)
tabs = leading_spaces // tab_width
remainder = leading_spaces % tab_width
result.append('\t' * tabs + ' ' * remainder + stripped)
return '\n'.join(result)
# Example: tab → 4 spaces
code_with_tabs = "def foo():\n\treturn 1"
print(repr(convert_indent(code_with_tabs, from_tab=True)))
# 'def foo():\n return 1'
# Example: spaces → tab (width=2)
code_with_spaces = "def bar():\n pass"
print(repr(convert_indent(code_with_spaces, from_tab=False, tab_width=2)))
# 'def bar():\n\tpass'package main
import (
"fmt"
"strings"
"unicode/utf8"
)
// TabToSpaces replaces each tab with `width` spaces.
func TabToSpaces(s string, width int) string {
return strings.ReplaceAll(s, "\t", strings.Repeat(" ", width))
}
// SpacesToTab replaces leading spaces (multiples of width) with tabs.
func SpacesToTab(s string, width int) string {
lines := strings.Split(s, "\n")
for i, line := range lines {
// Count leading spaces
leading := 0
for _, r := range line {
if r == ' ' {
leading++
} else {
break
}
}
if leading == 0 {
continue
}
tabs := leading / width
rem := leading % width
lines[i] = strings.Repeat("\t", tabs) + strings.Repeat(" ", rem) + line[leading:]
}
return strings.Join(lines, "\n")
}
func main() {
// Tab → 4 spaces
input1 := "func main() {\n\tfmt.Println(\"hi\")\n}"
fmt.Printf("%q\n", TabToSpaces(input1, 4))
// "func main() {\n fmt.Println(\"hi\")\n}"
// Spaces (width=2) → tab
input2 := "if true {\n return\n}"
fmt.Printf("%q\n", SpacesToTab(input2, 2))
// "if true {\n\treturn\n}"
}/**
* Convert indentation between tabs and spaces.
* @param {string} text - Input text
* @param {'tab2space'|'space2tab'} direction
* @param {number} tabWidth - Number of spaces per tab
* @returns {string}
*/
function convertIndent(text, direction, tabWidth = 4) {
if (direction === 'tab2space') {
return text.replace(/\t/g, ' '.repeat(tabWidth));
}
// space2tab: replace leading spaces (multiples of tabWidth) with tabs
return text.split('\n').map(line => {
const match = line.match(/^( *)/);
if (!match) return line;
const leadingSpaces = match[1].length;
const tabs = Math.floor(leadingSpaces / tabWidth);
const rem = leadingSpaces % tabWidth;
return '\t'.repeat(tabs) + ' '.repeat(rem) + line.slice(leadingSpaces);
}).join('\n');
}
// Example: tab → 4 spaces
console.log(convertIndent('function a() {\n\treturn 1;\n}', 'tab2space'));
// function a() {
// return 1;
// }
// Example: spaces (width=2) → tab
console.log(convertIndent('if (x) {\n console.log(1);\n}', 'space2tab', 2));
// if (x) {
// \tconsole.log(1);
// }常见问题
8 个高频疑问