【问题标题】:Replacing/removing excess white space between columns in a file替换/删除文件中列之间的多余空格
【发布时间】:2022-01-15 05:30:02
【问题描述】:

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

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。

【问题讨论】:

  • 您是否尝试用制表符替换最后一列(数字)之前的空格?
  • 最后一列后面真的有空格吗?
  • Benjamin W. 感谢您的回复。 Ed Morton 刚刚发布了回复。我是在这里发帖和回复的新手。感谢您抽出宝贵时间回答我的问题。 :)

标签: bash awk sed cut


【解决方案1】:

只需使用 awk:

$ awk -F'  +' -v OFS='\t' '{sub(/ +$/,""); $1=$1}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)
$1=$1}            # 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, 4th Edition》一书。

【讨论】:

  • 谢谢,成功了!你认为你能告诉我 awk 在这里做什么吗?分解命令?
【解决方案2】:

困难在于每行的单词数量不同。虽然您可以使用 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"

使用/输出示例

(使用您的输入文件)

$ 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。如果您有任何问题,请查看并告诉我。

【讨论】:

    【解决方案3】:
    sed -E 's/[ ][ ]+/\\t/g' filename > outfile
    

    注意:[ ]openBracket Space closeBracket

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

    双括号[ ][ ]+ 仅用于替换多个连续空格的制表符。

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

    【讨论】:

    • 要格式化代码行,缩进4-spaces,对于内联代码,将代码括在反引号 '`'
    • 空白字符不是正则表达式元字符,因此[&lt;blank&gt;] 完全等同于&lt;blank&gt;,因此您可以将[&lt;blank&gt;][&lt;blank&gt;]+ 更改为&lt;blank&gt;&lt;blank&gt;+。此外,OP 正在尝试获取制表符分隔的输出,而不是 "\t"-separated,所以不要逃避。
    • 是的,有几种方法可以编写正则表达式。对于任何阅读它的人来说,我并不认为“+”是两个空格后跟加号。而 [ ][ ]+ 更明显一些。
    • 此外,使用 -E 扩展正则表达式选项需要转义制表符 \\t。否则你不会在输出中得到标签。
    • @ChuckB 必须是特定于 sed 版本的东西,因为 GNU sed 并非如此。老实说,我无法想象为什么这对任何 sed 都有意义,但如果你这么说......
    【解决方案4】:

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

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

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

    最后一列之前的空白将被一个制表符替换,其余部分保持不变 - 请参阅通过管道传送到 cat -A 的输出以显示明确的行结尾,并查看^I 的制表符字符。

    如果每一行的末尾有没有个空格,这简化为

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

    请注意,某些 sed,尤其是 MacOS 中的 BSD sed,不能使用 \t 代替选项卡。在这种情况下,您必须改用'$'\t'''"$(printf '\t')"'

    【讨论】:

    • 再次感谢本杰明 W。我也会试试这个。
    【解决方案5】:

    另一种方法,gnu sedrev

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

    【讨论】:

    • 您好,karakfa,也感谢您的回复。 Ed Morton 的建议奏效了。我会在几次尝试你的方法并尝试回复。
    【解决方案6】:

    每行都有尾随空格。所以你可以像这样一次性完成两个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
    

    【讨论】:

      【解决方案7】:

      代码中

      简单且没有不可见的语义字符

          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 数据上进行测试。为了保持一致性,删除了尾随空格。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-02
        • 2014-08-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多