【问题标题】:Extract text with different delimiters提取具有不同分隔符的文本
【发布时间】:2013-02-27 00:18:09
【问题描述】:

我的文本文件看起来像这样

foo.en 14 :: xyz 1;foo bar 2;foofoo 5;bar 9
bar.es 18 :: foo bar 4;kjp bar 2;bar 6;barbar 8

忽略:: 分隔符之前的文本,是否有一个内衬unix 命令(允许许多管道)或一个内衬perl 脚本来提取文本,从而产生由; 分隔的唯一单词的输出?

xyz
foo bar
foofoo
bar
kjp bar
barbar

我尝试使用 python 脚本循环遍历文本文件,但我正在寻找一个单行的任务。

ans = set()
for line in open(textfile):
  ans.add(line.partition(" :: ")[1].split(";").split(" ")[:-1])

for a in ans:
  print a

【问题讨论】:

  • 我已经用 python 完成了它并遍历了文本文件。我只是在寻找一种更简单的方法。

标签: perl unix text-files delimiter


【解决方案1】:

使用 Perl:

perl -nle 's/.*?::\s*//;!$s{$_}++ and print for split /\s*\d+;?/' input

说明

s/.*?::\s*//;  # delete up to the first '::'

这部分:

!$s{$_}++ and print for split /\s*\d+;?/

可以这样改写:

foreach my $word (split /\s*\d+;?/) {   # for split /\s*\d+;?/
  if (not defined $seen{$word}}) {      # !$s{$_}
    print $word;                        # and print
  }
  $seen{$word}++;                       # $s{$_}++
}

由于!$s{$_}++ 中的增量是后增量,Perl 首先测试假条件,然后执行增量。未定义的哈希值具有值0。如果测试失败,即 $s{$_} 先前已递增,则由于 short circuiting 而跳过 and 部分。

【讨论】:

  • 尽管我很喜欢 perl,但@Floris 赢得了管道奖。如果我允许 2 ans =),请不要担心你是第二名
  • :) 只是比较输出
  • 他们都给出了相同的输出。 @perreal 不会获得无烟奖,lolz
  • 如果我能弄清楚它是如何工作的,我可能会投票支持这个答案......但没有给出解释。 !$s{$_}++ and print for split ???!!!我敢肯定它很聪明——我希望我也是。
  • @Floris,我添加了一些描述,希望足够了。
【解决方案2】:
cat textfile | sed 's/.*:://g' |  tr '[0-9]*;' '\n' | sort -u

解释:

sed 's/.*:://g'      Take everything up to and including `::` and replace it with nothing
tr '[0-9];' '\n'     Replace numbers and semicolon with newlines
sort -u              Sort, and return unique instances

我相信它确实会产生一个排序的输出......

【讨论】:

  • 还有问题是foo bar不会被输出,它会输出foobar for foo bar
  • @2er0 - 你在这两个方面都是对的 - 谢谢!我看到您在编辑的同时进行了编辑以纠正 (foo bar) 的错误...我添加了排序并认为它现在是正确的。
  • grep -o -E '\(.*\);' 似乎不对。应该是grep -o -E '\(.*\)\;'
  • 使用tr 命令简化了最后一个grep 和两个seds,并结合了sort 和uniq。现在更紧凑了
  • 谢谢@sputnick。我猜这意味着你认为我在抽烟?或者抽什么东西? ...
【解决方案3】:

你可以试试这个:

$ awk -F ' :: ' '{print $2}' input.txt | grep -oP '[^0-9;]+' | sort -u
bar 
barbar 
foo bar 
foofoo 
kjp bar 
xyz 

如果你的短语包含数字,试试这个 正则表达式:'[^;]+?(?=\s+\d+(;|$))'

【讨论】:

    【解决方案4】:

    只有

    $ awk -F' :: ' '{
        gsub(/[0-9]+/, "")
        split($2, arr, /;/ )
        for (a in arr) arr2[arr[a]]=""
    }
    END{
        for (i in arr2) print i
    }' textfile.txt
    

    还有一个单行版本:

     awk -F' :: ' '{gsub(/[0-9]+/, "");split($2, arr, /;/ );for (a in arr) arr2[arr[a]]="";}END{for (i in arr2) print i}' textfile.txt
    

    【讨论】:

      猜你喜欢
      • 2017-06-25
      • 1970-01-01
      • 1970-01-01
      • 2018-05-22
      • 2019-11-26
      • 1970-01-01
      • 2012-08-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多