如何仅替换前导制表符(包括一些空格字符后的制表符)?

如何仅替换前导制表符(包括一些空格字符后的制表符)?

我有一些由制表符或空格或两者缩进的文件。我想将前导制表符转换为空格(1 个制表符转换为 4 个空格)。这包括一些前导空格后的制表符。下面是一些输入行和预期结果的一些示例。

+----+----------------+----------------+
|编号|原线|预期结果 |
+----+----------------+----------------+
| 1 | \t␣xxx | ␣␣␣␣␣xxx |
| 2 | ␣␣␣\txxx | ␣␣␣␣␣␣␣xxx |
| 3 | \t␣\txxx | ␣␣␣␣␣␣␣␣␣xxx |
| 4 | \tx\txx | ␣␣␣␣x\txx |
+----+----------------+----------------+

我无法expand在这里使用该命令,因为它无法处理空格和制表符混合的情况。下面是一个例子。

user1@ubuntu$ printf "\t  \txxx" | od -t a
0000000  ht  sp  sp  ht   x   x   x
0000007
user1@ubuntu$ printf "\t  \txxx" | expand -i -t 4 | od -t a
0000000  sp  sp  sp  sp  sp  sp  sp  sp   x   x   x
0000013
user1@ubuntu$ 

正如您所看到的,原始字符串中的两个空格被简单地删除了。如何解决我的问题?我在这个网站上读过其他类似的问题,但它们与我的问题并不完全相同。

答案1

您可以使用 sed (我用来cat -T显示文件,因为它将选项卡显示为^I):

$ cat -T file
^I abc
^I  ^Ixde^Inot
$ sed ':x;s|^\( *\)\t|\1    |;tx' file | cat -T
     abc
          xde^Inot

不幸的是,as 选项卡的解释\t是 GNU sed 扩展,而不是 POSIX 指定的。但是,您可以解决这个问题printf正如 Gilles 所示使用和写:

sed ":x;s|^\( *\)$(printf '\t')|\1    |;tx" file

sed 在那里做什么?

  • s|^\( *\)\t|\1 |

如果 sed 发现制表符后跟零个或多个空格字符锚定到行开头,它将用 4 个空格替换该制表符。该对\(\)界定由 再现的匹配组(由零个或多个前面的空格字符组成)\1

  • tx

如果进行了替换,请转到标签:x。否则,继续下一行。

答案2

要将第一个非空格字符之前的所有制表符替换为 4 个空格,请尝试:

perl -pe '/^(\s+)/; $k=$1; $k=~s/\t/    /g; s/^\s+/$k/'file > newfile

该脚本将首先找到所有前导空格(空格、制表符和其他任何内容)并将其保存为$k.然后,它将所有制表符替换为 4 个空格,$k最后将所有前导空格替换为 的当前值$k

要仅限制空格和制表符,您可以执行以下操作:

perl -pe '/^([ \t]+)/; $k=$1; $k=~s/\t/    /g; s/^\s+/$k/'file > newfile

在您的示例字符串上运行,这些解决方案会产生:

$  printf '\t xxx\n   \txxx\n\t \txxx\n\tx\txx\n'  | perl -pe '/^(\s+)/; $k=$1; $k=~s/\t/    /g; s/^\s+/$k/' | od -t a
0000000  sp  sp  sp  sp  sp   x   x   x  nl  sp  sp  sp  sp  sp  sp  sp
0000020   x   x   x  nl  sp  sp  sp  sp  sp  sp  sp  sp  sp   x   x   x
0000040  nl  sp  sp  sp  sp   x  ht   x   x  nl
0000052

相关内容