【问题标题】:Split data using sed or awk使用 sed 或 awk 拆分数据
【发布时间】:2013-12-16 12:23:21
【问题描述】:

我有很多数据要以 CSV 格式拆分。我的源数据格式如下:

* USER 'field1' 'mail1@domain.com' 'field3'
* USER 'field1' 'mail2@domain.com' 'field3'
* USER 'field1' 'mail3@domain.com' 'field3'

这就是我想要得到的输出:

field1;mail1@domain.com;field3
field1;mail2@domain.com;field3
field1;mail3@domain.com;field3

规则

  1. 行首的* USER必须明显去掉;
  2. field1field3 可以是电子邮件地址,也可以包含'
  3. field1 可能为空 ''
  4. 第二个字段始终是电子邮件地址;
  5. 每个字段的开头和结尾都有'

我的想法是剥离* USERsed -e 's/^* USER //' 可能是一个起点),然后在“中心”字段中“找到”邮件,然后将左侧和右侧捕获为两个变量。最后一件事应该是去掉变量上的开头和结尾'。 不幸的是,我没有这个级别的 sed 或 awk 知识。关于如何实现这一点的任何想法?


这里是一个例子

* USER '' 'alberto.cordini@generaligroup.com' 'CORDINI ALBERTO'
* USER 'moglie delmonte daniele' 'anna.borghi@rpos.com' 'Anna Borghi'
* USER '' 'annamaria.cravero@generaligroup.com' 'CRAVERO ANNA MARIA'
* USER '' 'patrizia.dagostino@generaligroup.com' 'D'AGOSTINO PATRIZIA'
* USER '' 'piero.depra@generaligroup.com' 'DE PRA' PIERO'
* USER '' 'viviana.dingeo@generaligroup.com' 'D'INGEO VIVIANA'

【问题讨论】:

  • 如果您能够添加一个小样本,其中包含您添加到帖子中的案例/规则,那肯定会更容易提供帮助。
  • 我在下面贴了一个例子
  • 为什么使用' 而不是" 来包围可能包含' 的名称? ...它在自找麻烦。

标签: regex bash shell sed awk


【解决方案1】:

更新:您可以将此 awk 用于提供的输入:

awk -F " '" '{gsub(/^ +| +$/, "", $3);
              s=sprintf("%s;%s;%s;", $2,$3,$4); gsub(/'"'"';/, ";", s); print s}' file
;alberto.cordini@generaligroup.com;CORDINI ALBERTO;
moglie delmonte daniele;anna.borghi@rpos.com;Anna Borghi;
;annamaria.cravero@generaligroup.com;CRAVERO ANNA MARIA;
;patrizia.dagostino@generaligroup.com;D'AGOSTINO PATRIZIA;
;piero.depra@generaligroup.com;DE PRA' PIERO;
;viviana.dingeo@generaligroup.com;D'INGEO VIVIANA;

【讨论】:

  • 它没有按预期工作。看下面的例子
  • 我必须将 ' 保留在字段内部(而不是外部)
  • 哦,完美!还有一个问题:是否可以“修剪”电子邮件地址/$3?
  • 修剪是指从电子邮件字段中修剪空格?
  • 巧妙使用" '"分隔符。
【解决方案2】:

简单地说:

$ awk '{print $2,$4,$6}' FS="'" OFS=";" file 
field1;mail1@domain.com;field3
field1;mail2@domain.com;field3
field1;mail3@domain.com;field3

【讨论】:

  • 好吧。只需稍作改动即可使用 .FS="\047"。有些系统不接受这个。至少我的solaris盒子
  • 我喜欢你使用凝视和结束撇号作为 FS 的事实。这一直有效,直到用户 O'Hara 使用他的真实姓名(Google xkcd Johnny Tables 的警示故事)。仍然得到我的投票......
  • 它没有按预期工作。看下面的例子
  • 您在 answer-that-should-have-been-an-edit 中看到 'D'INGEO VIVIANA' 了吗?
【解决方案3】:

您可以使用 sed 和 awk,这会起作用,但像您一样,我使用它们的频率不够高(而且我发现它们很笨重)。如果您需要一个可以放入脚本中一直运行的解决方案,那么 Ruby 解决方案怎么样,我使用正则表达式,但您不必:

样本数据.txt

* USER 'field1' 'mail1@domain.com' 'field3'
* USER 'field1' 'mail2@domain.com' 'field3'
* USER 'field1' 'mail3@domain.com' 'field3'

解析.rb

#!/usr/bin/env ruby

$stdin.each_line do |e|
    matches = e.match /\*\ USER\ '([\w]*)'\ '([\w\@\.]*)'\ '([\w]*)'/
    if matches != nil
        puts "#{matches[1]};#{matches[2]};#{matches[3]}"
    end
end

从终端/命令行:

cat sample-data.txt | ruby parse.rb

附言对我来说,如果这是一次性的问题,我会在 Windows 中使用 Notepad++。我会打开文件,然后录制一个宏,然后将宏播放到文件末尾,完成。

【讨论】:

  • 没问题!只是想给你一个替代方案。
【解决方案4】:
 sed "s/²/²S/g;s/\\'/²q/g;s/\*[[:blank:]]USER[[:blank:]]\{1,\}'\([^']*\)'[[:blank:]]*'\([^']*\)'[[:blank:]]*'\(.*\)'[[:blank:]]*$/\1;\2;\3/;s/²q/\\'/g;s/²S/²/g" YourFile.csv

假设没有包含 ' 的字段 1 被/未被转义

【讨论】:

    【解决方案5】:

    一个sed 示例,它依赖于引号分隔的字段之间存在单个空格这一事实。如果不是这种情况,则需要对其进行修改以使其更加“灵活”。

    为了避免 shell 引号转义,这是一种丑陋的体验,我会在文件中放入一个衬里。 -r 使其使用扩展的正则表达式(避免引用()s)。 field1 和 field3 中的单引号被正则表达式贪婪保留(吃掉所有东西,包括引号,直到最后一个引号:)

    sed -r -f s.sed samp.csv
    

    s.sed:

    s/\* USER '(.*)' '([^']*)' '(.*)'/\1;\2;\3/
    

    【讨论】:

      猜你喜欢
      • 2017-08-25
      • 1970-01-01
      • 1970-01-01
      • 2012-07-11
      • 1970-01-01
      • 1970-01-01
      • 2012-05-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多