sed:全局替换时忽略前导空格

sed:全局替换时忽略前导空格

我正在尝试编写一个 sed 命令来替换文件中的过多空格。每个单词之间只能有一个空格,但前导空格和制表符应单独保留。所以文件:

     This is     an indented      paragraph. The   indentation   should not be changed.
This is the     second   line  of the    paragraph. 

会变成:

     This is an indented paragraph. The indentation should not be changed.
This is the second line of the paragraph.

我尝试过的变体

/^[ \t]*/!s/[ \t]+/ /g

任何想法,将不胜感激。

答案1

$ sed 's/\>[[:blank:]]\{1,\}/ /g' file
     This is an indented paragraph. The indentation should not be changed.
This is the second line of the paragraph.

我使用的表达式匹配一个或多个[[:blank:]](空格或制表符)一句话之后,并将它们替换为一个空格。匹配\>单词字符和非单词字符之间的零宽度边界。

这是使用 OpenBSD 的本机测试的,但我认为它也sed应该适用于 GNU 。 sedGNUsed还用于\b匹配单词边界。

您还可以sed -E将其缩短为

sed -E 's/\>[[:blank:]]+/ /g' file

同样,如果\>GNU 不适用于您sed,请改用\b


请注意,虽然上面以正确的方式对示例文本进行了排序,但它并没有相当用于删除标点符号后的空格,如第一个句子之后

     This is     an indented      paragraph.        The   indentation   should not be changed.
This is the     second   line  of the    paragraph.

为此,一个稍微复杂的变体就可以解决问题:

$ sed -E 's/([^[:blank:]])[[:blank:]]+/\1 /g' file
     This is an indented paragraph. The indentation should not be changed.
This is the second line of the paragraph.

这会将任何非空白字符后跟一个或多个空白字符替换为非空白字符和一个空格。

或者,使用标准sed(以及一个非常小的优化,因为它只会在存在时进行替换两个或更多非空格/制表符之后的空格/制表符),

$ sed 's/\([^[:blank:]]\)[[:blank:]]\{2,\}/\1 /g' file
     This is an indented paragraph. The indentation should not be changed.
This is the second line of the paragraph.

答案2

POSIXly:

sed 's/\([^[:space:]]\)[[:space:]]\{1,\}/\1 /g; s/[[:space:]]*$//'

它将非空白后面的一个或多个空白字符的任何序列替换为该非空白和一个 SPC 字符,并删除尾随空白字符,这将覆盖空白行和带有尾随空白的行(包括在来自 Microsoft 文本文件的行尾)。

相关内容