【问题标题】:How to print the row number and starting location of a pattern when multiple matches per row are present?当每行存在多个匹配项时,如何打印模式的行号和起始位置?
【发布时间】:2022-01-26 08:03:05
【问题描述】:

我想使用 awk 来匹配一个大文件中出现的所有模式。对于每个匹配,我想打印行号和模式沿行的起始位置(xy 坐标排序)。每行中出现多次该模式。 我发现this 有点相关的问题。

到目前为止,我只在每行的第一个(最左边)出现时才做到这一点。举个例子:

echo xyzABCdefghiABCdefghiABCdef | awk 'match($0, /ABC/) {print NR, RSTART } ' 

结果输出是:

1 4

但我希望是这样的:

1 4
1 13
1 22

我尝试使用拆分而不是匹配。我设法识别出所有事件,但 RSTART 丢失并打印为“0”。

echo xyzABCdefghiABCdefghiABCdef | awk ' { split($0,t, /ABC/,m) ; for (i=1; i in m; i++) print (NR, RSTART) } '

输出:

1 0
1 0
1 0

任何建议将不胜感激。我不限于使用 awk,但 awk 解决方案将不胜感激。 此外,在我的情况下,要匹配的模式将是正则表达式 (/A.C/)。 谢谢

【问题讨论】:

  • 如何处理重叠?例如,假设输入是 01010,而您正在寻找 010 ... 1 或 2 个匹配项?
  • 在我目前的情况下,我确信文件中没有重叠。假设我认为最好有办法将重叠处理为两个单独的匹配。
  • 请阅读how-do-i-find-the-text-that-matches-a-pattern,然后在您的问题中出现的任何地方用字符串或正则表达式替换“模式”一词。您还应该在搜索“模式”中使用正则表达式元字符,并将这些元字符包含在您的示例输入/输出中,这样我们就有了可以真正测试的东西。
  • 还在您的示例中包含重叠字符串,例如在字符串 ABCABCABCABC 中搜索 ABCABC 以显示输出是否应为 1 1\n1 71 1\n1 4\n1 7 或其他内容。正如所写的那样,您可以获得从示例输入中产生预期输出的答案,但实际上并没有做任何您需要的事情。

标签: bash awk split


【解决方案1】:

这可能是你想要做的:

echo xyzABCdefghiABCdefghiABCdef | 
awk '{ begpos=1
       while (match(substr($0, begpos), /ABC/)) {
           print NR, begpos + RSTART - 1
           begpos += RLENGTH + RSTART - 1
       }
     }'

【讨论】:

    【解决方案2】:

    使用gnu awk 的另一个选项可能是使用带有正则表达式的拆分。

    使用split 函数,第三个字段是fieldsep 数组,第四个字段是seps 数组,您可以使用它们来计算位置。

    echo xyzABCdefghiABCdefghiABCdef | 
    awk ' { 
      n=split($0, a, /ABC/, seps); pos=1
      for(i=1; i<n; i++){
        pos += length(a[i])
        print NR, pos
        pos += length(seps[i])
      } 
    }'
    

    输出

    1 4
    1 13
    1 22
    

    【讨论】:

      【解决方案3】:

      使用您展示的示例,请尝试关注awk 代码。

      awk '
      {
        prev=0
        while(match($0,/ABC/)){
          $0=substr($0,RSTART+RLENGTH)
          print FNR,prev+RSTART
          prev+=RSTART+2
        }
      }
      '  Input_file
      

      说明:为上述添加详细说明。

      awk '                              ##Starting awk program from here.
      {
        prev=0                           ##Setting prev variable to 0 here.
        while(match($0,/ABC/)){          ##Using while loop to match ABC string and it runs till ABC match is ture in current line.
          $0=substr($0,RSTART+RLENGTH)   ##Re-creating current line by assigning value of rest of line(which starts after match of ABC).
          print FNR,prev+RSTART          ##Printing line number along with prev+RSTART value here.
          prev+=RSTART+2                 ##Setting prev to prev+RSTART+2 here.
        }
      }
      '  Input_file                      ##Mentioning Input_file name here.
      

      【讨论】:

      • 这行得通,谢谢你的解释!
      • 我只是想补充一点,`prev+=RSTART+2`应该根据模式的长度来改变。如果 patterna 的长度为 3 个字符,则 2 有效。
      • @RicGGG,是的,您可以将其更改为 prev+=RSTART+RLENGTH-1 我没有检查它,但它应该可以工作。
      • 是的,我看到了链接。不过,我的声望太低,无法投票。
      【解决方案4】:

      awk判断一个字符串的坐标:

      echo "xyzABCdefghiABCdefghiABCdef" \
        | awk -v s="ABC" 'BEGIN{ len=length(s) }
            {
              for(i=1; i<=length($0); i++){
                if(substr($0, i, len)==s){
                  print NR, i
                }
              }
            }'
      

      输出:

      1 4 1 13 1 22

      一行:

      echo xyzABCdefghiABCdefghiABCdef | awk -v s="ABC" 'BEGIN{ len=length(s) } { for(i=1; i<=length($0); i++){ if(substr($0,i,len)==s) { print NR,i } } }'
      

      来源:Find position of character with awk

      【讨论】:

      • 这在我发布的示例中非常有效,但是当我的模式是正则表达式(例如 /A.C/ )时,它无法找到匹配项。我想它只需要稍微调整一下。
      【解决方案5】:

      一个使用split()awk 想法和length() 结果的一些切片:

      ptn='ABC'
      
      echo xyzABCdefghiABCdefghiABCdef | 
      awk -v ptn="${ptn}" '
      { pos=-(length(ptn)-1)
        n=split($0,arr,ptn)
        for (i=1;i<n;i++) { 
            pos+=length(arr[i] ptn)
            print NR,pos
        }
      }'
      

      这会生成:

      1 4
      1 13
      1 22
      

      【讨论】:

      • 谢谢。这是我最终在代码中使用的解决方案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-01-04
      • 1970-01-01
      • 2017-05-16
      • 1970-01-01
      • 2017-02-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多