【问题标题】:space delimited file handling空格分隔文件处理
【发布时间】:2014-07-01 05:50:48
【问题描述】:

我在一个以空格分隔的文件中有一家公司的内幕交易。示例数据如下所示:

1 Gilliland Michael S January 2,2013 20,000 19
2 Still George J Jr January 2,2013 20,000 19
3 Bishkin S. James February 1,2013 150,000 21
4 Mellin Mark P May 28,2013 238,000 25.26

Col1 是我不需要打印的 Serial#
Col2 是进行交易的人的姓名。此列不一致。它有名字、名字和中间名的首字母,对于一些内部人员来说也有称呼(先生、小博士等)
col3 是日期格式 Month Day,Year
col4 是交易的股票数量
col5 是购买或出售股票的价格。

我需要你们帮助分别打印每个列的值。感谢您的帮助。

【问题讨论】:

  • 如果您的字段中有空格并且您的列是用空格分隔的,您将无法获得 clean 解决方案。理想情况下,您希望能够以tsv 格式提取数据。此外,在向 StackOverflow 寻求帮助之前,通常会展示您尝试过的内容。
  • 你的意思是你想要一个打印名字的命令,另一个打印日期的命令,等等?
  • 您可以控制数据的外观吗?
  • 不,很遗憾没有。这就是我们从源接收数据的方式。
  • 您是否使用 AWK 来尝试获取值?我没有这方面的经验,所以我想知道你是否知道它是否具有正则表达式功能?这可能是你唯一的希望。

标签: regex awk sed


【解决方案1】:

统计读取的字段总数;这与非名称字段的数量之间的差异为您提供了名称的宽度。

#!/bin/bash
# uses bash features, so needs a /bin/bash shebang, not /bin/sh

# read all fields into an array
while read -r -a fields; do

  # calculate name width assuming 5 non-name fields
  name_width=$(( ${#fields[@]} - 5 ))
  cur_field=0

  # read initial serial number
  ser_id=${fields[cur_field]}; (( ++cur_field ))

  # read name
  name=''
  for ((i=0; i<name_width; i++)); do
    name+=" ${fields[cur_field]}"; (( ++cur_field ))
  done
  name=${name# } # trim leading space

  # date spans two fields due to containing a space
  date=${fields[cur_field]}; (( ++cur_field ))
  date+=" ${fields[cur_field]}"; (( ++cur_field ))

  # final fields are one span each
  num_shares=${fields[cur_field]}; (( ++cur_field ))
  price=${fields[cur_field]}; (( ++cur_field ))

  # print in newline-delimited form
  printf '%s\n' "$ser_id" "$name" "$date" "$num_shares" "$price" ""
done

如下运行(如果你将脚本保存为process):

./process <input.txt >output.txt

【讨论】:

  • 哇!查尔斯,你以我从未想过的方式做到了。我正在尝试使用 sed 和 awk。我是一名数据库专家,并试图在数据库中加载数据。感谢您的快速回复,但我想我会选择 awk。我尝试了您和 Jotne 提供的两种解决方案。我想我会选择awk。很棒的东西。
【解决方案2】:

perl 可能会更容易一些。

perl -lane '
    @date = splice @F, -4, 2;
    @left = splice @F, -2, 2;
    splice @F, 0, 1;
    print join "|", "@F", "@date", @left
' file
Gilliland Michael S|January 2,2013|20,000|19
Still George J Jr|January 2,2013|20,000|19
Bishkin S. James|February 1,2013|150,000|21
Mellin Mark P|May 28,2013|238,000|25.26

您可以根据需要更改join 中的分隔符。

【讨论】:

  • +1;我认为这可能是这里最易读的解决方案(并且对我口中说出的话感到惊讶......可读的 perl,奇迹会永远不会停止吗?)
  • 谢谢@CharlesDuffy。我感谢你投的信任票。正如这位智者曾经说过的那样,Perl 旨在为您提供多种方式来做任何事情,因此请考虑选择最易读的一种。 我会尽量遵循它。 (虽然没有promises;)
【解决方案3】:

这是使用awk分隔的数据

awk '{c1=$1;c5=$NF;c4=$(NF-1);c3=$(NF-3)FS$(NF-2);$1=$NF=$(NF-1)=$(NF-2)=$(NF-3)="";gsub(/^ | *$/,"");c2=$0;print c1"|"c2"|"c3"|"c4"|"c5}' file
1|Gilliland Michael S|January 2,2013|20,000|19
2|Still George J Jr|January 2,2013|20,000|19
3|Bishkin S. James|February 1,2013|150,000|21
4|Mellin Mark P|May 28,2013|238,000|25.26

你知道你的数据在变量c1c5

或者更好的显示在这里:

awk '{c1=$1;c5=$NF;c4=$(NF-1);c3=$(NF-3)FS$(NF-2);$1=$NF=$(NF-1)=$(NF-2)=$(NF-3)="";gsub(/^ | *$/,"");c2=$0;print c1"|"c2"|"c3"|"c4"|"c5}' file | column -t -s "|"
1  Gilliland Michael S  January 2,2013   20,000   19
2  Still George J Jr    January 2,2013   20,000   19
3  Bishkin S. James     February 1,2013  150,000  21
4  Mellin Mark P        May 28,2013      238,000  25.26

【讨论】:

  • 非常感谢 Jotne。你惊人的。在我在这里发布问题之前,我花了几个小时来解决这个问题。
猜你喜欢
  • 1970-01-01
  • 2018-09-01
  • 1970-01-01
  • 2021-05-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多