我正在编写一个在二进制数组(位图文件)中搜索位模式的函数。模式的大小为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
那么检测字符串中这种模式的最有效方法是什么?通过移位模式和字符串的位,然后对它们执行XOR?
答案 0 :(得分:0)
查找给定模式可以用与该模式中的位数相同的步骤数完成。我不知道这是检测模式的最有效方法,但对于不太大的模式,它可能具有竞争力。
例如,考虑您的模式01000000。
必须在bs的位串中找到它,我们将bs [i]称为bs的第i位。
该图案在给定位置iiff
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]为true(1)
并且bs [i + 7]为false(0)
这可以变成逻辑表达式
~ bs[i] & ~ bs[i+1] & ~ bs[i+2] & ~ bs[i+3] & ~ bs[i+4] & ~ bs[i+5] & bs[i+6] & ~ bs[i+7]
模式中有0的地方有逻辑补码。
可以通过右移将其重写以得到表达式:
~ bs[i] & ~ ((bs>>)[i]) & ~ ((bs>>2)[i]) & ~ ((bs>>3)[i]) & ~ ((bs>>4)[i]) & ~ ((bs>>5)[i]) & ((bs>>6)[i]) & ~ ((bs>>7)[i])
其中(bs>>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,我们都将结果与位串的正确移位版本进行AND,如果未设置pattern的lsb,则将其与移位后的位串的补数进行AND。
补充是通过与(pattern&1)-1
进行异或来完成的。如果设置了lsb,则它是1-1 = 0(同一性)的异或,否则是-1(等于〜)的异或。
请注意,较高位可能存在错误匹配,因为以某种方式人为地将位串左移了(patternsize-1)
零,这可能会导致位串/模式的某种组合出现问题。这就是最终掩码清除(patternsize-1)匹配的最左位的原因,因为不可能找到超出32位模式大小的匹配。因此,match
与(2 ^(32-(patternsize-1))相乘,该数字是1组成的数字,patternsize-1的零在最左边。