【问题标题】:record the lines in which each word in a given file appears using awk使用 awk 记录给定文件中每个单词出现的行
【发布时间】:2014-10-13 22:27:23
【问题描述】:

在执行此操作时遇到一些问题。输出需要采用以下格式:在每一行上,首先打印一个单词,然后是一个冒号“:”,然后是一个空格,然后是该单词出现的行号列表(以逗号分隔)。如果一个词在一行中出现多次,它应该只报告该行的一次。

命令行:index.awk test1.txt > new.output.txt

我的代码(当前):

    #!/bin/awk -f


Begin {lineCount=1}                    # start line count at 1

{         
    for (i = 1; i <= NF; i++)          # loop through starting with postition 1
       for ( j = 2; j <= NF; j++)      # have something to compare  
          if ( $i == $j )              # see if they match
              print $i ":" lineCount   # if they do print the word and line number
              lineCount++              # increment the line number

}

您会在下面的示例输出中注意到它完全跳过了输入文本文件的第一行。它从那里正确计数。如果单词出现不止一次,我如何打印它?另外,awk 是否有一个本机函数可以解释错误字符,例如标点符号、数字、[]、() 等...

(EDIT: gsub(regexp, replacement, target) 可以从文本中省略这些错误字符。

示例输入:我想打印出每个单词,并且 单词出现的对应行。我需要确定 我在打印出来时省略了字符串中的标点符号。作为 好吧,我需要确定这个词是否在一行中出现了不止一次 不要将行号打印两次。

SAMPLE OUTPUT: 

I:
would:
like:
to:
print:
out:
each:
word:
and,:
the:1
corresponding:
lines:
which:
the:
word:
occurs:
on.:
I:1
need:1
to:1
make:1
sure:1
.....ect (outputs the line numbers correctly from here)

【问题讨论】:

  • 一些示例输入也很有用。
  • 感谢您的建议,刚刚添加了一些示例输入。
  • 有什么建议吗? @TomFenech
  • 为什么and,on. 被认为是“单词”?定义一个“词”对你意味着什么。
  • @Ryan 识别单词是大局,其余的都是微不足道的。更新您的问题以显示您认为难以处理的一些输入案例(例如,Theretherethere's 是同一个词吗?尾随的 s 是一个词吗?7 是一个词吗? 7th?)和你真正想要的输出呢。

标签: shell awk scripting gawk scripting-language


【解决方案1】:
awk '{delete u;for (i=1;i<=NF;i++) u[$i]=1; for (i in u) cnt[i]=cnt[i]NR","} END{for (i in cnt) {sub(/,$/,"",cnt[i]); printf "%s: %s\n",i,cnt[i]}}' input

作为一个例子(比你的例子短一些):

$ cat file
I and I and I went
here and here and there
and then home

$ awk '{delete u;for (i=1;i<=NF;i++) u[$i]=1; for (i in u) cnt[i]=cnt[i]NR","} END{for (i in cnt) {sub(/,$/,"",cnt[i]); printf "%s: %s\n",i,cnt[i]}}' file
there: 2
went: 1
here: 2
and: 1,2,3
then: 3
I: 1
home: 3

工作原理

该程序使用三个变量:iucntu 用于在每一行创建一个唯一的单词列表。 cnt 用于跟踪每个单词的行号。 i 在循环中用作临时变量。

这段代码使用了awk 隐式循环文件中每一行的事实。读取最后一行后,将执行 END 子句,显示结果。

依次考虑每个命令:

  • delete u

    在每一行的开头,我们希望数组 u 为空。

  • for (i=1;i&lt;=NF;i++) u[$i]=1

    在数组u 中为该行中的每个单词创建一个条目。

  • for (i in u) cnt[i]=cnt[i]NR","

    对于该行的每个单词,将当前行号添加到数组cnt

  • END{for (i in cnt) {sub(/,$/,"",cnt[i]); printf "%s: %s\n",i,cnt[i]}

    处理完最后一行后,打印出数组cnt 中的每个条目。 cnt 中的每个条目都有一个额外的尾随逗号。使用sub 命令删除该逗号。然后printf 格式化输出。

改进

假设我们想忽略大小写的差异。为此,我们可以将所有单词转换为小写:

$0=tolower($0)

如果我们也想忽略标点符号,我们可以删除它:

gsub(/[-.,"!?/]/," ")

把它们放在一起:

awk '{delete u;$0=tolower($0);gsub(/[-.,"!?/]/," ");for (i=1;i<=NF;i++) u[$i]=1; for (i in u) cnt[i]=cnt[i]NR","} END{for (i in cnt) {sub(/,$/,"",cnt[i]); printf "%s: %s\n",i,cnt[i]}}' file

【讨论】:

  • 我很感激!那是非常有用的,最重要的是它有效!我希望我可以投票给你,不幸的是我需要一个 15 的代表来做到这一点:/ 这样一个新手。 @John1024
  • @Ryan :您可以通过选择此答案左上角上下投票计数器中间的复选标记来“接受”此答案。
  • @John1024 sub(/[-.,"!?/," ") 不会从输出中删除标点符号。例如,如果我有一个字符串和/或作为输入和/或算作一个单词,而不是将和/或分成两个单独的单词“and”和“or”。同样,标点符号仍然坚持单词“end”。“,and”...ect
  • @Ryan 哎呀。那应该是gsub 而不是sub。至于and/or,被删除的标点只是gsub命令中正则表达式指定的标点。那是你的选择。我更新了答案,将/ 包含在删除的字符中。
猜你喜欢
  • 2016-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-21
  • 1970-01-01
  • 2017-09-21
相关资源
最近更新 更多