在grep中搜索字符串模式以获得滑动窗口

时间:2014-09-23 05:49:43

标签: bash shell grep

我编写了使用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

8 个答案:

答案 0 :(得分:1)

怎么样,

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

我认为这并不简单。

无论如何......它会让你想要的东西回归!

答案 1 :(得分:1)

您可以使用:

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

答案 2 :(得分:1)

使用perl:

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

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

答案 3 :(得分:1)

如果使用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

答案 4 :(得分:0)

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

$ 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

答案 5 :(得分:0)

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

答案 6 :(得分:0)

这是一种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循环打印。

答案 7 :(得分:0)

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