AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 568767
Accepted
Johnny Rollerfeet
Johnny Rollerfeet
Asked: 2020-02-21 09:55:09 +0800 CST2020-02-21 09:55:09 +0800 CST 2020-02-21 09:55:09 +0800 CST

文本文件中所有重复单词的位置(按字数)

  • 772

我想找到一个单词在文本文件中出现的位置——比如一个单词出现在文本中的单词数量——对于该单词的所有实例,但我什至不确定从哪里开始。我想我需要一个循环,以及 grep 和 wc 的某种组合。

例如,这里有一篇关于 iPhone 11 的文章:

周二,该公司表示,其入门级手机 iPhone 11 的起价为 700 美元,而上一款同类机型的起价为 750 美元,这表明苹果正在关注那些不会竞相购买更昂贵手机的消费者。年。

苹果将​​其更先进的机型 iPhone 11 Pro 和 iPhone 11 Pro Max 的起价保持在 1,000 美元和 1,100 美元。该公司在其硅谷园区举行的 90 分钟新闻发布会上推出了这些新手机。

正文共有81个字。

jaireaux@macbook:~$ wc -w temp.txt 
      81 temp.txt

“iPhone”这个词出现了 3 次。

jaireaux@macbook:~$ grep -o -i iphone temp.txt | wc -w
       3

我想要的输出是这样的:

jaireaux@macbook:~$ whereword iPhone temp.txt 
      24
      54
      57

我会怎么做才能得到那个输出?

grep wc
  • 9 9 个回答
  • 776 Views

9 个回答

  • Voted
  1. Best Answer
    terdon
    2020-02-21T10:23:48+08:002020-02-21T10:23:48+08:00

    这是使用 GNU 工具的一种方法:

    $ tr ' ' '\n' < file | tr -d '[:punct:]' | grep . | grep -nFx iPhone
    25:iPhone
    54:iPhone
    58:iPhone
    

    第一个tr用换行符替换所有空格,然后第二个删除所有标点符号(以便iPhone,可以作为单词找到)。确保我们跳过任何空grep .行(我们不想计算那些)grep -n并将行号附加到输出中。然后,-F告诉grep不要将其输入视为正则表达式,并且-x它应该只找到跨越整行的匹配项(因此这job不会算作 的匹配项jobs)。请注意,您在问题中给出的数字相差 1。

    如果您只想要数字,您可以添加另一个步骤:

    $ tr ' ' '\n' < file | tr -d '[:punct:]' | grep . | grep -nFx iPhone | cut -d: -f1
    25
    54
    58
    

    正如评论中所指出的,这仍然会有“单词”的问题,例如aren'tor double-barreled。您可以使用以下方法进行改进:

    tr '[[:space:][:punct:]]' '\n' < file | grep . | grep -nFx iPhone
    
    • 6
  2. Paul_Pedant
    2020-02-21T10:01:20+08:002020-02-21T10:01:20+08:00

    使用 tr 命令将所有空格替换为单个换行符(使用挤压选项)。

    将其传递给 nl -ba,它会按顺序对每一行(以及单词)进行编号。

    将它传递给 grep -F 以获得您想要的单词。这将仅显示这些单词的数字和文本。

    awk 也可以在一个进程中执行此操作,但可能看起来更复杂。

    • 3
  3. schrodingerscatcuriosity
    2020-02-21T11:05:02+08:002020-02-21T11:05:02+08:00

    一个替代方案sed:

    sed -e '/^$/d' -e 's/^[[:blank:]]*//g' < file | sed 's/[[:blank:]]/\n/g' | grep -ion "iphone"
    

    输出:

    25:iPhone
    54:iPhone
    58:iPhone
    
    • 2
  4. user373503
    2020-02-21T11:45:17+08:002020-02-21T11:45:17+08:00

    我正在尝试(现在!)类似的东西:字数。像这样,您会看到“单词”的样子:

    ]# cat iphone | tr -s [:space:] '\n' |sort|uniq -c|sort -n  |grep phone
          1 phone,
          1 phones
          1 phones,
    
    ]# cat iphone | tr -d [:punct:] | tr -s [:space:] '\n' |sort|uniq -c|sort -n  |grep phone
          1 phone
          2 phones
    

    这个技巧(?)|sort|uniq -c|sort -n提供了一个很好的概述。

      2 Apple
      2 Pro
      2 a
      2 and
      2 company
      2 more
      2 phones
      2 to
      3 11
      3 iPhone
      3 its
      4 at
      6 the
    

    这看起来不错,但在顶部:

      1 1000
      1 1100
      1 700
      1 750
      1 90minute
    

    美元、逗号和减号都不见了……至少看起来很干净。


    一个快速的解决方法是定义一些不会出现在(自然语言)“单词”中的常见插句。然后在一侧或两侧使用 ^anchoring$。

    ]# cat iphone | tr -d '.,;"!?' | tr -s [:space:] '\n' | grep -n phone 
    21:phones
    30:phone
    72:phones
    
    ]# cat iphone | tr -d '.,;"!?' | tr -s [:space:] '\n' | grep -n ^phone$
    30:phone
    

    你可以找到小数字之类的东西:

    ]# cat iphone | tr -d '.,;"!?' | tr -s [:space:] '\n' | grep -n '1[012]'
    27:11
    56:11
    60:11
    64:$1000
    66:$1100
    

    tr|sed|grep(最好的简单解决方案)

    这会处理一些情况(以及这个@*#!文本中的所有情况;)并给出 81 个单词,例如wc. 编号必须没有前导空格才能正确。愚蠢的(但不是太)拆分由 完成tr,然后sed删除尾随标点符号:这里只有逗号和句点。然后是grep数字和过滤器即兴发挥。

    ]# <iphone  tr -s ' \t' '\n' | sed -E 's/(.+)[.,]/\1/' | grep -En  '[\$-]|campus|i*[pP]hone$|entry' 
    25:iPhone
    28:entry-level
    29:phone
    33:$700
    36:$750
    54:iPhone
    58:iPhone
    63:$1000
    65:$1,100
    74:90-minute
    81:campus
    

    这找不到复数形式i*[pP]hone$。这不适用于尾随逗号,请参见上文。逗号不见了,除了价格。

    要分隔“入门级”,您只需将减号添加到trSET1。

    我认为这是每个工具执行一个自然步骤的一个很好的例子。

    • 0
  5. hellork
    2020-02-22T02:19:50+08:002020-02-22T02:19:50+08:00

    创建一个函数。

    $ whereword(){ grep -ion "$1" -<<<$(egrep -o "[^[:blank:]]+" "$2"); }
    
    $ whereword iPhone tmp.txt
    25:iPhone
    54:iPhone
    58:iPhone
    
    $ whereword "aren't" tmp.txt
    14:aren't
    
    • 0
  6. mosvy
    2020-02-22T03:05:22+08:002020-02-22T03:05:22+08:00

    [我想知道你是如何得到这些数字的——如果我选择第一个文本iPhone并将其传送到wc -w,我得到 24。在第二个之前iPhone,我得到 53,而不是 54。所以它们不匹配,无论在哪个我改变他们的方向]

    假设a)计数应该是从 1 开始的,b)单词用空格分隔(使用与 相同的“单词”定义wc -w),并且c)使用 GNU grep,这会更简单:

    grep -Po '\S+' file | grep -n iPhone
    
    25:iPhone
    54:iPhone
    58:iPhone
    

    [也将匹配iPhoneyor XiPhone,但不匹配iphone; 如果您想让它不区分大小写地匹配整个单词,请使用... | grep -nwi iPhone]

    这也更容易适应“词”的不同定义;例如,对于 word = 除控件、空格(分隔符)和标点之外的任何字符的序列:

    grep -Po '[^\pC\pZ\pP]+' file | grep -n iPhone
    
    26:iPhone
    56:iPhone
    60:iPhone
    

    或 word = 字母、标记、数字和一些符号和标点符号,如$, _, '+ 使用不当的“左引号”(U+2019)代替撇号aren’t:

    grep -Po "[\pL\pM\pN'\x{2019}\$]+" file | grep -n iPhone
    
    25:iPhone
    55:iPhone
    59:iPhone
    
    • 0
  7. Ed Morton
    2020-02-22T06:32:51+08:002020-02-22T06:32:51+08:00

    使用“单词”的最常见解释来解析英文文本(即什么grep -w认为一个单词以及\w在工具中接受它作为正则表达式中的“单词组成字符”的含义),即“一​​串字母、数字和/或下划线字符”aren’t不是一个词,所以:

    $ cat tst.awk
    BEGIN { FS="[^[:alnum:]_]+" }
    {
        for (i=1; i<=NF; i++) {
            numWords++
            if ($i == tgt) {
                print numWords
            }
        }
    }
    
    $ awk -v tgt="iPhone" -f tst.awk file
    26
    57
    61
    
    $ awk -v tgt="aren’t" -f tst.awk file
    $
    
    $ awk -v tgt="aren" -f tst.awk file
    14
    

    或者如果aren’t是一个词,那么:

    $ cat tst.awk
    BEGIN { FS="[^[:alnum:]_’]+" }
    {
        for (i=1; i<=NF; i++) {
            numWords++
            if ($i == tgt) {
                print numWords
            }
        }
    }
    
    $ awk -v tgt="iPhone" -f tst.awk file
    25
    56
    60
    
    $ awk -v tgt="aren’t" -f tst.awk file
    14
    
    $ awk -v tgt="aren" -f tst.awk file
    $
    

    正确的解决方案完全取决于您对“单词”的定义。例如,以上都不$1,000是一个词——如果这对您的应用程序来说是个问题,那么 idk 。如果是,这里的脚本可能更接近您对“单词”的解释(使用 GNU awk 进行 FPAT):

    $ cat tst.awk
    BEGIN {
        FPAT = "([[:alpha:]]+[’'][[:alpha:]]+)|([$]?[0-9]+(,[0-9]+)*([.][0-9]+)?%?)|([[:alnum:]_]+)"
    }
    {
        for (i=1; i<=NF; i++) {
            numWords++
            print numWords, "<" $i ">"
            if ($i == tgt) {
                print numWords
            }
        }
    }
    

    这是它在您的示例输入中识别的“单词”:

    $ awk -f tst.awk file
    1 <On>
    2 <Tuesday>
    3 <in>
    4 <a>
    5 <sign>
    6 <that>
    7 <Apple>
    8 <is>
    9 <paying>
    10 <attention>
    11 <to>
    12 <consumers>
    13 <who>
    14 <aren’t>
    15 <racing>
    16 <to>
    17 <buy>
    18 <more>
    19 <expensive>
    20 <phones>
    21 <the>
    22 <company>
    23 <said>
    24 <the>
    25 <iPhone>
    26 <11>
    27 <its>
    28 <entry>
    29 <level>
    30 <phone>
    31 <would>
    32 <start>
    33 <at>
    34 <$700>
    35 <compared>
    36 <with>
    37 <$750>
    38 <for>
    39 <the>
    40 <comparable>
    41 <model>
    42 <last>
    43 <year>
    44 <Apple>
    45 <kept>
    46 <the>
    47 <starting>
    48 <prices>
    49 <of>
    50 <its>
    51 <more>
    52 <advanced>
    53 <models>
    54 <the>
    55 <iPhone>
    56 <11>
    57 <Pro>
    58 <and>
    59 <iPhone>
    60 <11>
    61 <Pro>
    62 <Max>
    63 <at>
    64 <$1,000>
    65 <and>
    66 <$1,100>
    67 <The>
    68 <company>
    69 <unveiled>
    70 <the>
    71 <new>
    72 <phones>
    73 <at>
    74 <a>
    75 <90>
    76 <minute>
    77 <press>
    78 <event>
    79 <at>
    80 <its>
    81 <Silicon>
    82 <Valley>
    83 <campus>
    
    • 0
  8. bu5hman
    2020-02-22T10:44:35+08:002020-02-22T10:44:35+08:00

    一个 GNUawk替代方案,在单个空格上拆分或句号和换行符的组合

    awk 'BEGIN{RS=" |\\.\n"} $0~/iPhone/{print NR}' file1
    
    • 0
  9. user232326
    2020-02-22T14:19:47+08:002020-02-22T14:19:47+08:00

    为了跟上一个词就是一个词的想法wc:

    单词是由空格分隔的非零长度字符序列。

    我们可以用 将文件分成每行中的非空格序列grep -Eo '[^[:space:]]+' file,然后删除tr -d '[:punct:]'(仍然存在的)标点符号,最后,通过感兴趣的单词 grep(不区分大小写)grep -in 'phone'

    $ grep -Eo '[^[:space:]]+' file | tr -d '[:punct:]' | grep -in 'phone'
    20:phones
    25:iPhone
    29:phone
    54:iPhone
    58:iPhone
    71:phones
    

    请注意,在这种情况下删除标点符号不会改变单词的行位置。该-i选项同时选择Phone和phone,如图所示。

    对于单词的情况iPhone:

    $ grep -Eo '[^[:space:]]+' file | tr -d '[:punct:]' | grep -in 'iphone'
    25:iPhone
    54:iPhone
    58:iPhone
    

    那应该是正确的单词编号(不是您写的 24、54 和 58)。

    • 0

相关问题

  • 来自 `service | 的意外结果 grep`

  • 读取带有单词的文本文件及其出现次数和排序的打印输出

  • 命令 ls | grep 只显示目录(当它也应该显示文件时)

  • grep 什么时候计数,什么时候不计数

  • grep --line-buffered 直到 X 行?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve