我想确定用空格缩进的源文件中使用的制表符宽度。这对于具有特别规则缩进的文件并不难,其中前导空格仅用于缩进,始终是制表符宽度的倍数,并且缩进每次增加一级。但是许多文件会与这种常规缩进有所不同,通常是为了某种形式的垂直对齐。因此,我正在寻找一种很好的启发式方法来估计使用的标签宽度,从而允许不规则缩进的一些可能性。
这样做的动机是为 SubEthaEdit 编辑器编写扩展。不幸的是,SubEthaEdit 没有使选项卡宽度可用于脚本,所以我将根据文本猜测它。
一个合适的启发式应该:
- 性能足够好,可以交互使用。我不认为这会是一个问题,如果需要,可以只使用部分文本。
- 语言独立。
- 返回最长的合适标签宽度。例如,如果每个缩进实际上是两倍的级别,则任何具有四个空格的制表符宽度的文件也可能是具有两个空格制表符的文件。显然,四个空格将是正确的选择。
- 如果压痕完全规则,请始终正确处理。
一些简化因素:
- 可以假设至少一行是缩进的。
- 可以假定制表符宽度至少为两个空格。
- 可以安全地假设缩进仅使用空格完成。并不是我对tab有什么反对——恰恰相反,我会先检查是否有用于缩进的tab,并单独处理。这确实意味着可能无法正确处理缩进混合制表符和空格,但我认为这并不重要。
- 可以假设没有仅包含空格的行。
- 并非所有语言都需要正确处理。例如,像 lisp 和 go 这样的语言的成功或失败将完全无关紧要,因为它们通常不是手动缩进的。
- 不需要完美。如果偶尔需要手动调整几行,世界不会结束。
你会采取什么方法,你认为它的优点和缺点是什么?
如果您想在答案中提供工作代码,最好的方法可能是使用一个 shell 脚本来读取源文件stdin
并将制表符宽度写入stdout
. 伪代码或清晰的文字描述也可以。
一些结果
为了测试不同的策略,我们可以将不同的策略应用于语言分布的标准库中的文件,因为它们可能遵循语言的标准缩进。我将考虑 Python 2.7 和 Ruby 1.8 库(系统框架安装在 Mac OS X 10.7 上),它们的预期选项卡宽度分别为 4 和 2。不包括以制表符开头的行或没有以至少两个空格开头的行的文件。
Python:
Right None Wrong
Mode: 2523 1 102
First: 2169 1 456
No-long (12): 2529 9 88
No-long (8): 2535 16 75
LR (changes): 2509 1 116
LR (indent): 1533 1 1092
Doublecheck (10): 2480 15 130
Doublecheck (20): 2509 15 101
红宝石:
Right None Wrong
Mode: 594 29 51
First: 578 0 54
No-long (12): 595 29 50
No-long (8): 597 29 48
LR (changes): 585 0 47
LR (indent): 496 0 136
Doublecheck (10): 610 0 22
Doublecheck (20): 609 0 23
在这些表中,“正确”应被视为确定语言标准制表符宽度,“错误”应视为非零制表符宽度不等于语言标准宽度,而“无”应视为零制表符宽度或否回答。“模式”是选择最频繁发生的缩进变化的策略;“First”是对第一行缩进进行缩进;“不长”是FastAl排除缩进大的行并采取模式的策略,数字表示允许的最大缩进变化;“LR”是Patrick87基于线性回归的策略,有基于行间缩进变化和行绝对缩进的变体;“Doublecheck”(无法抗拒双关语!)是 Mark 对 FastAl 的修改