用 spaces 替换制表符以保持 n-space 对齐

Replacing tab with spaces to maintain n-space alignment

我正在尝试自动比较两组包含按列组织的数据的文件。似乎有三个主要问题使这个问题变得棘手:

  1. 集合 A 和集合 B 的列顺序不同
  2. A 组使用制表符,B 组使用 spaces
  3. 在 A 组中,有些列包含空白,B 组中,它们包含默认值。

我尝试编写一些简单的 shell 脚本来将集合 A 重新排列到正确排序的列中,例如awk '{print substr([=12=], 10, 10) substr([=12=], 20, 10)} 等,但是在这组文件中使用制表符意味着列以不一致的字符编号开头。

我认为最简单的解决方案是将制表符替换为 spaces,然后使用 awk 重新排列数据,如上所示。我应该如何用等于到达下一个制表位所需数量的 space 来替换制表符(为此,我们假设 8)。

用设置的 spaces 替换一个选项卡显然是行不通的,正如我在下面测试的那样。

$ echo "A\tB\nA \tB\nA  \tB\nA   \tB\n" > test
$ cat test
A       B
A       B
A       B
A       B
$ cat test | sed 's/\t/    /g'
A    B
A     B
A      B
A       B

显然,这可以通过编写一些代码来确定制表符所在的位置,然后填充适当数量的 space 字符来实现对齐来解决,但似乎应该有一个比我可能缺少的更简单的解决方案。 (或者打开vim中的每个文件并使用:retab,但必须有更好的选择!)

注意:由于某些数据集中存在空白,我无法column重新排列数据。

由于制表符前有空格,您可以使用此 sed:

sed $'s/ *\t/    /g' test
A    B
A    B
A    B
A    B 

这还将用 4 个空格替换制表符前的 0 个或更多空格。

给定以下 awk 脚本:

BEGIN {
  tabSize = 8;
}
{
  str = [=10=];
  idx = index(str, "\t");
  while (idx > 0) {
    left = substr(str, 0, idx);
    right = substr(str, idx + 1);
    spaces = sprintf("% " ((tabSize + 1) - (idx % tabSize)) "s", "");
    str = left spaces right;
    idx = index(str, "\t");
  }
  print str;
}

你可以执行这个命令:

cat test | awk -f tab2spaces.awk

此脚本适用于任何内容。