【问题标题】:Searching a string pattern in grep for a sliding window在 grep 中搜索字符串模式以查找滑动窗口
【发布时间】:2014-09-23 22:49:30
【问题描述】:

我已经编写了使用grep 搜索和计算字符串出现次数的代码。但是,它没有考虑到滑动窗口。

试过了:

grep -E -o "(A|B){2}" datafile | sort | uniq -c

数据文件:

AABBABAABBBA

输出:

2 AA
1 AB
1 BA
2 BB

预期输出:

2 AA
3 BA
3 AB
2 BB

【问题讨论】:

  • 不应该有3 BB吗?
  • 所以输出不需要按任何庄园排序?

标签: bash shell grep


【解决方案1】:

怎么样,

for i in {"AA","AB","BA","BB"}; do echo "AABBABAABBBA" | grep -o $i; done | sort | uniq -c

我觉得不简单。

无论如何...它会返回你想要的输出!

【讨论】:

    【解决方案2】:

    你可以使用:

    awk 'BEGIN {FS=""}{for(i=2; i<=NF; i++) 
                print $(i-1) $i}' datafile | grep -Eo "[AB]{2}" | sort | uniq -c
    2 AA
    3 AB
    3 BA
    3 BB
    

    【讨论】:

      【解决方案3】:

      使用 perl:

      $ echo AABBABAABBBA | perl -nE 'say for /(?<=([AB]{2}))/g' | sort | uniq -c
          2 AA
          3 AB
          3 BA
          3 BB
      

      注意:以上解决方案的灵感来自this answer...

      【讨论】:

        【解决方案4】:

        如果使用bash 4.0 或更高版本,您可以使用关联数组来跟踪每个唯一的两个字符集及其计数:

        declare -A list
        while read -r line; do
            for ((i=0;i<=$((${#line}-2));i++)); do
                ref="${line:$i:2}"
                if [[ ${!list[@]} != *"$ref"* ]]; then
                    list["$ref"]=1
                else
                    ((list["$ref"]++))
                fi
            done
        done < file
        for index in "${!list[@]}"; do
            echo "${list[$index]} $index"
        done
        

        输出:

        3 AB
        2 AA
        3 BB
        3 BA
        

        【讨论】:

          【解决方案5】:

          为什么您希望输出与您显示的一样?分解:

          $ echo AABBABAABBBA | grep -E -o "(A|B){2}"
          AA
          BB
          AB
          AA
          BB
          BA
          

          现在sort:

          $ echo AABBABAABBBA | grep -E -o "(A|B){2}" | sort
          AA
          AA
          AB
          BA
          BB
          BB
          

          注意: AB 出现在BA 之前,然后排序。现在找到uniq

          $ echo AABBABAABBBA | grep -E -o "(A|B){2}" | sort | uniq -c
              2 AA
              1 AB
              1 BA
              2 BB
          

          AB 总是在sort 之前BA(除非相反)。如果您反转sort,您将反转整个答案。

          要创建你的滑动寡妇,你可以沿着字符串走:

          str=AABBABAABBBA; for ((i=0; i<$((${#str}-1)); i++)); do \
          printf "%s\n" "${str:$i:2}"; done | sort | uniq -c
          

          输出:

            2 AA
            3 AB
            3 BA
            3 BB
          

          或者按照 jaypal 的建议:

          echo "AABBABAABBBA" | awk -v FS= \
          '{for(i=1;i<NF;i++)a[$i,$(i+1)]++}END{for(x in a) print a[x],x}'
          
          2 AA
          3 AB
          3 BA
          3 BB
          

          【讨论】:

          • 我相信 OP 希望对字符串中的每两个字符进行递归。所以AABBABAABBBA 应该输出AA, AB, BB, BA ... etc 然后计数`em。
          • 哦...,{2} 表示与前面的表达式完全匹配 2 次以及 -o 不会这样做。它只是抓取2 字符匹配,沿着字符串向下移动,将每个匹配放在单独的行上。鉴于您的意见,我会再看一看。
          • 当然,我一直在考虑echo "AABBABAABBBA" | awk -v FS= '{for(i=1;i&lt;NF;i++)a[$i,$(i+1)]++}END{for(x in a) print a[x],x}',但我被推迟了我的 OP 在起草一个好问题方面缺乏尝试。 :)
          • 无论你如何分割它,你仍然会想出相同的AA AB BA BB( str=AABBABAABBBA; for ((i=0; i&lt;$((${#str}-1)); i++)); do printf "%s\n" "${str:$i:2}"; done | sort | uniq -c )
          【解决方案6】:

          Bash 解决方案:

          #!/bin/bash
          while read str
          do
             len=$(echo "${#str}")
             i=0
             #Convert the string in to array
             ar=($(while [[ "$len" -gt "$i" ]];do echo "${str:i:1}";let "i = $i + 1";done))
             k=0
             #iterate through array and print the string for piping it into grep
             for ((j=0;j<${#ar[@]};j++))
             do
                k=$((k = j+1))
                [ "$k" -lt "$len" ] && echo "${ar[j]}${ar[k]}"
             done
          done < datafile > datafile1
          grep -hoP '\b\w+\b' < datafile1 | sort | uniq -c
          

          【讨论】:

            【解决方案7】:

            这是一种 perl 方式:

            $ echo AABBABAABBBA | 
                perl -F"" -alne 'for($i=0;$i<$#F;$i++){$k{$F[$i].$F[$i+1]}++}
                                 print "$_ : $k{$_}" for keys(%k); '
            AA : 2
            BB : 3
            AB : 3
            BA : 3
            

            说明

            -F 将字段分隔符设置为空字符串,-an 导致每个输入行根据-F 的值拆分到@F 数组中。结果是一个数组,其中每个元素都是输入的单个字母。然后我们创建一个哈希,其键是每组 2 个连续字母 ($F[$i] . $F[$i+1]),然后每次找到两个字母组合时递增相应的值。最后,在for 循环中打印键及其值。

            【讨论】:

              【解决方案8】:

              Bash 解决方案

              str="AABBABAABBBA"
              for i in `seq 1 ${#str}`; do
                 echo $str | cut -c${i}-
              done | grep -Eo '^(A|B){2}' | sort | uniq -c
              

              for 循环构建原始字符串的所有较短的尾子字符串

              AABBABAABBBA
              ABBABAABBBA
              BBABAABBBA
              BABAABBBA
              ABAABBBA
              BAABBBA
              AABBBA
              ABBBA
              BBBA
              BBA
              BA
              A
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2014-04-02
                • 1970-01-01
                • 2015-03-20
                • 1970-01-01
                • 2012-11-01
                相关资源
                最近更新 更多