gpt4 book ai didi

c++ - 匹配位串

转载 作者:可可西里 更新时间:2023-11-01 18:37:08 26 4
gpt4 key购买 nike

我需要实现一种字符串搜索算法,用于在位文本中查找位模式(匹配项可能不是字节/字对齐的)。对于初学者,我实现了 Boyer-Moore 算法,但比较单个位对于我的目的来说太慢了。因此,我尝试实现一个基于 block 的版本,该版本将比较整个字节/单词,如 this paper 中所述。 ,但它变得复杂且难以管理(部分原因是我不完全理解我在做什么。)

有没有人很好地实现了这样的算法?

我的具体用例是模式长度 N >= 32,文本窗口 2N,以及打包到 int 中的位。此外,在这种情况下,N 是字符大小 N % 8 == 0 的倍数。我预处理一次并多次使用更改文本,例如 Boyer-Moore。我只需要第一场比赛。性能是关键。

编辑: 在成功实现 Blocked Boyer-Moore 算法后,我发现没有任何改进(我的一点一点的版本更快!)这可能是我自己的错误,因为我一直在努力我的大脑在上面并将其优化到没有很多评论就没有意义的地步,但它仍然很慢。 Here是的。

最佳答案

概览

我是 SO 社区的新手,但我期待着回馈一些东西。

有趣的问题。我整理了一个实现,它只进行基于字节的比较(借助于预先计算的位模式和位掩码),而不是在比较时执行昂贵的位操作。因此,它应该相当快。它没有实现为 Boyer-Moore algorithm 讨论的任何转换规则(性能优化)从而可以进一步改进。

尽管此实现确实取决于模式位的数量 % CHAR_BIT == 0——在 8 位机器上,满足 N % 8 == 0 的标准,该实现将找到非字节对齐的位模式. (它目前还需要 8 位字符( CHAR_BIT == 8 ),但在极少数情况下您的系统不使用 8 位字符,通过将所有数组/vector 从 uint8_t 更改为 char 并调整它们包含的值以反射(reflect)正确的位数。)

鉴于搜索不进行任何位操作(除了预先计算的字节掩码之外),它的性能应该非常好。

算法总结

简而言之,指定要搜索的模式,实现将其移位一位并记录移位后的模式。它还计算移位模式的掩码,对于非字节对齐的位模式,比较开始和结束时的一些位将需要被忽略以实现正确的行为。

搜索每个移位位置中的所有模式位,直到找到匹配项或到达数据缓冲区的末尾。

//
// BitStringMatch.cpp
//

#include "stdafx.h"
#include <iostream>
#include <cstdint>
#include <vector>
#include <memory>
#include <cassert>

int _tmain(int argc, _TCHAR* argv[])
{
//Enter text and pattern data as appropriate for your application. This implementation assumes pattern bits % CHAR_BIT == 0
uint8_t text[] = { 0xcc, 0xcc, 0xcc, 0x5f, 0xe0, 0x1f, 0xe0, 0x0c }; //1010 1010, 1010 1010, 1010 1010, 010*1 1111, 1110 0000, 0001 1111, 1110 0000, 000*0 1010
uint8_t pattern[] = { 0xff, 0x00, 0xff, 0x00 }; //Set pattern to 1111 1111, 0000 0000, 1111 1111, 0000 0000

assert( CHAR_BIT == 8 ); //Sanity check
assert ( sizeof( text ) >= sizeof( pattern ) ); //Sanity check

std::vector< std::vector< uint8_t > > shiftedPatterns( CHAR_BIT, std::vector< uint8_t >( sizeof( pattern ) + 1, 0 ) ); //+1 to accomodate bit shifting of CHAR_BIT bits.
std::vector< std::pair< uint8_t, uint8_t > > compareMasks( CHAR_BIT, std::pair< uint8_t, uint8_t >( 0xff, 0x00 ) );

//Initialize pattern shifting through all bit positions
for( size_t i = 0; i < sizeof( pattern ); ++i ) //Start by initializing the unshifted pattern
{
shiftedPatterns[ 0 ][ i ] = pattern[ i ];
}

for( size_t i = 1; i < CHAR_BIT; ++i ) //Initialize the other patterns, shifting the previous vector pattern to the right by 1 bit position
{
compareMasks[ i ].first >>= i; //Set the bits to consider in the first...
compareMasks[ i ].second = 0xff << ( CHAR_BIT - i ); //and last bytes of the pattern

bool underflow = false;
for( size_t j = 0; j < sizeof( pattern ) + 1; ++j )
{
bool thisUnderflow = shiftedPatterns[ i - 1 ][ j ] & 0x01 ? true : false;
shiftedPatterns[ i ][ j ] = shiftedPatterns[ i - 1][ j ] >> 1;

if( underflow ) //Previous byte shifted out a 1; shift in a 1
{
shiftedPatterns[ i ][ j ] |= 0x80; //Set MSb to 1
}

underflow = thisUnderflow;
}
}

//Search text for pattern
size_t maxTextPos = sizeof( text ) - sizeof( pattern );
size_t byte = 0;
bool match = false;
for( size_t byte = 0; byte <= maxTextPos && !match; ++byte )
{
for( size_t bit = 0; bit < CHAR_BIT && ( byte < maxTextPos || ( byte == maxTextPos && bit < 1 ) ); ++bit )
{
//Compare first byte of pattern
if( ( shiftedPatterns[ bit ][ 0 ] & compareMasks[ bit ].first ) != ( text[ byte ] & compareMasks[ bit ].first ) )
{
continue;
}

size_t foo = sizeof( pattern );
//Compare all middle bytes of pattern
bool matchInProgress = true;
for( size_t pos = 1; pos < sizeof( pattern ) && matchInProgress; ++pos )
{
matchInProgress = shiftedPatterns[ bit ][ pos ] == text[ byte + pos ];
}
if( !matchInProgress )
{
continue;
}

if( bit != 0 ) //If compare failed or we're comparing the unshifted pattern, there's no need to compare final pattern buffer byte
{
if( ( shiftedPatterns[ bit ][ sizeof( pattern ) ] & compareMasks[ bit ].second ) != ( text[ byte + sizeof( pattern ) ] & compareMasks[ bit ].second ) )
{
continue;
};
}

//We found a match!
match = true; //Abandon search
std::cout << "Match found! Pattern begins at byte index " << byte << ", bit position " << CHAR_BIT - bit - 1 << ".\n";
break;
}
}
//If no match
if( !match )
{
std::cout << "No match found.\n";
}

std::cout << "\nPress a key to exit...";
std::getchar();

return 0;
}

希望对您有所帮助。

关于c++ - 匹配位串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12103438/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com