Replacing/removing 文件中列之间的多余白色 space

Replacing/removing excess white space between columns in a file

我正在尝试解析具有类似内容的文件:

I am a string         12831928  
I am another string           41327318   
A set of strings      39842938  
Another string           3242342  

我希望输出文件以制表符分隔:

I am a string\t12831928  
I am another string\t41327318   
A set of strings\t39842938  
Another string\t3242342 

我试过以下方法:

sed 's/\s+/\t/g' filename > outfile

我也试过cut和awk。

sed -E 's/[ ][ ]+/\t/g' filename > outfile

注意:[ ]openBracket Space closeBracket

-E 用于扩展正则表达式支持。

双括号[ ][ ]+仅用于替换连续1个以上的制表符space。

在 MacOS 和 Ubuntu 版本的 sed 上测试。

困难在于单词数量的变化 per-line。虽然您可以使用 awk 来处理这个问题,但一个简单的脚本将一行中的每个单词读入一个数组,然后 tab-分隔每行中的最后一个单词也可以工作:

#!/bin/bash

fn="${1:-/dev/stdin}"

while read -r line || test -n "$line"; do
    arr=( $(echo "$line") )
    nword=${#arr[@]}
    for ((i = 0; i < nword - 1; i++)); do
        test "$i" -eq '0' && word="${arr[i]}" || word=" ${arr[i]}"
        printf "%s" "$word"
    done
    printf "\t%s\n" "${arr[i]}"
done < "$fn"

例子Use/Output

(使用您的输入文件)

$ bash rfmttab.sh < dat/tabfile.txt
I am a string   12831928
I am another string     41327318
A set of strings        39842938
Another string  3242342

每个数字都是来自字符串其余部分的 tab-delimited。仔细阅读,如果您有任何问题,请告诉我。

您输入的每行末尾都有空格,这使事情变得比没有空格更困难。此 sed 命令将用制表符替换最后一列之前的空格:

$ sed 's/[[:blank:]]*\([^[:blank:]]*[[:blank:]]*\)$/\t/' infile | cat -A
I am a string^I12831928  $
I am another string^I41327318   $
A set of strings^I39842938  $
Another string^I3242342  $

这匹配 - 锚定在行尾 - 空白,non-blanks 和再次空白,每个零个或多个。最后一列和捕获后的可选空白。

最后一列之前的空格随后被单个制表符替换,其余部分保持不变 – 请参阅管道输出到 cat -A 以显示明确的行结尾和 ^I 制表符。

如果每行末尾没有个空格,则简化为

sed 's/[[:blank:]]*\([^[:blank:]]*\)$/\t/' infile

请注意,某些 seds,尤其是 MacOS 中的 BSD sed,不能在替换中使用 \t 作为制表符。在这种情况下,您必须改用 '$'\t'''"$(printf '\t')"'

另一种方法,gnu sedrev

$ rev file | sed -r 's/ +/\t/1' | rev

只需使用 awk:

$ awk -F'  +' -v OFS='\t' '{sub(/ +$/,""); =}1' file
I am a string   12831928
I am another string     41327318
A set of strings        39842938
Another string  3242342

细分:

-F'  +'           # tell awk that input fields (FS) are separated by 2 or more blanks
-v OFS='\t'       # tell awk that output fields are separated by tabs
'{sub(/ +$/,"");  # remove all trailing blank spaces from the current record (line)
=}            # recompile the current record (line) replacing FSs by OFSs
1'                # idiomatic: any true condition invokes the default action of "print"

我强烈推荐 Arnold Robbins 的《Effective Awk Programming》第 4 版。

每行都有尾随空格。所以你可以像这样一次做两个 sed 表达式:

$ sed -E -e 's/ +$//' -e $'s/  +/\t/' /tmp/file  
I am a string   12831928
I am another string 41327318
A set of strings    39842938
Another string  3242342

注意 $'s/ +/\t/':这告诉 bash 在调用 sed 之前用实际制表符替换 \t

要显示这些删除和 \t 插入在正确的位置,您可以这样做:

$ sed -E -e 's/ +$/X/' -e $'s/  +/Y/' /tmp/file  
I am a stringY12831928X
I am another stringY41327318X
A set of stringsY39842938X
Another stringY3242342X

简单且无隐形语义字符代码中:

    perl -lpe 's/\s+$//; s/\s\s+/\t/' filename

解释:

    Options:
      -l: remove LF during processing (in this case)
      -p: loop over records (like awk) and print
      -e: code follows

    Code:
      remove trailing whitespace
      change two or more whitespace to tab

已在 OP 数据上进行测试。为了保持一致性,删除了尾随空格。