【问题标题】:Search for pattern in binary array在二进制数组中搜索模式
【发布时间】:2019-10-23 17:51:01
【问题描述】:

我正在编写一个函数来在二进制数组(位图文件)中搜索位模式。模式的大小为 5 到 8 位长。我已经实现了这个函数来测试数组和模式中的每一位。但是,它并没有应有的效率。

首先我想用 C 来实现这段代码。



Point* FindPattern(imgInfo* pImg, int pSize, int* ptrn, Point* pDst, int* fCnt)
{
    int i, j, k, l;
    int mask;
    int rx = pSize >> 16;
    int ry = pSize & 0xFFFF;

    *fCnt = 0;
    for (i=0; i < pImg->height - ry; ++i)
        for (j=0; j < pImg->width - rx; ++j)
        {
            // for a rectangle with upper lefr corner in (i,j)
            // check if there is pattern in image
            for (k=0; k < ry; ++k)
            {
                mask = 1 << (rx - 1);
                for (l=0; l < rx; ++l, mask >>= 1)
                    if (GetPixel(pImg, j+l, i+k) != ((ptrn[k] & mask) != 0))
                        break;
                if (l < rx) // pattern not found
                    break;
            }
            if (k >= ry) //pattern found
            {
                pDst[*fCnt].x = j;
                pDst[*fCnt].y = i;
                ++(*fCnt);
            }
        }

例如我有这样的二进制字符串:1111 1111 1010 0000 0111 1111 1111 1111

我正在寻找模式:0100 0000

那么在字符串中检测这种模式的最有效方法是什么?通过移动模式和字符串的位而不是对它们执行异或?

【问题讨论】:

    标签: arrays search binary pattern-matching


    【解决方案1】:

    查找给定模式的步骤数等于模式中的位数。我不知道这是否是检测模式的最有效方法,但对于不太大的模式,它可能具有竞争力。

    例如,考虑您的模式 0100 0000。
    它必须在位串 bs 中找到,我们称 bs[i] 为 bs 的第 i 位。
    模式在给定位置匹配当且当

    bs[i] 为假 (0)
    而 bs[i+1] 为假 (0)
    而 bs[i+2] 为假 (0)
    而 bs[i+3] 为假 (0)
    而 bs[i+4] 为假 (0)
    而 bs[i+5] 为假 (0)
    并且 bs[i+6] 为真 (1)
    bs[i+7] 为假 (0)

    这可以转成逻辑表达式
    ~ bs[i] &amp; ~ bs[i+1] &amp; ~ bs[i+2] &amp; ~ bs[i+3] &amp; ~ bs[i+4] &amp; ~ bs[i+5] &amp; bs[i+6] &amp; ~ bs[i+7]
    当模式中有 0 时,哪里有逻辑补码。

    这可以用右位移重写得到表达式:
    ~ bs[i] &amp; ~ ((bs&gt;&gt;)[i]) &amp; ~ ((bs&gt;&gt;2)[i]) &amp; ~ ((bs&gt;&gt;3)[i]) &amp; ~ ((bs&gt;&gt;4)[i]) &amp; ~ ((bs&gt;&gt;5)[i]) &amp; ((bs&gt;&gt;6)[i]) &amp; ~ ((bs&gt;&gt;7)[i])
    其中(bs&gt;&gt;k)[i]是bs的第i位向右移动k步。

    由此我们可以推导出以下C代码

    #include <stdio.h>
    
    unsigned int findpattern(unsigned int bitstring, unsigned int pattern, 
                             unsigned int patternsize) {
      unsigned int match=~0;
      for(int i=0; i<patternsize; i++){
        match &= ((pattern&0x1)-1) ^ (bitstring);
        pattern >>=1;
        bitstring >>=1;
      }
    
      return match;
    }
    
    int main() {
      unsigned int bitstring=0xffa07fff;
      unsigned int pattern=0x40;
    
      unsigned int match=findpattern(bitstring,pattern,8);
    
      if (! match) 
        printf("No match for %x in %x\n",pattern, bitstring);
      else 
        printf("Matches found for %x in %x : %.8x\n", pattern, bitstring, match);
    }
    
    

    函数findpattern 返回一个int,如果在位置i 找到模式,则设置第i 位。没有找到模式匹配为零。

    这个想法只是通过右移模式来扫描模式的连续位。在任何时候,如果设置了 lsb,我们将结果与正确移位的位串版本进行与,如果未设置模式的 lsb,我们将其与移位位串的补码进行与。
    互补是通过与(pattern&amp;1)-1 异或来完成的。如果设置了 lsb,则为 1-1=0(身份)的异或,否则为 -1(等价于 ~)的异或。

    请注意,较高位中可能存在错误匹配,因为位串以某种方式被左侧的(patternsize-1) 零人工扩展,这可能会导致位串/模式的某些组合出现问题。这就是最终掩码清除(pattersize-1)匹配的最左边位的原因,因为不可能找到超过位 32-patternsize 的匹配。出于这个原因,match 与 (2^(32-(patternsize-1)) 相加,这是一个由 1 组成的数字,patternsize-1 在最左边的位置为零。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-17
      • 1970-01-01
      • 2010-12-05
      • 1970-01-01
      相关资源
      最近更新 更多