天天看點

适應adblock plus 規則的簡單正規表達式比對

adblock plus定義的廣告過濾清單非常好用,這裡分析一下adblock plus的廣告過濾規則

! 開始表示注釋

* 通配符,比對任何字元串

@@ 以此開頭表示白名單,

| 以此開始或者結束表示開始處或者結束處嚴格比對,沒有其他内容了

|| 以此開頭會忽略協定規則進行比對,比如忽略http,https等

^ 分隔符比對除數字,字母,-,.,%以外的其他字元

$ 指明後面的是過濾類型,比如是是image還是script等

按照adblock plus的說法,這些最終都轉換成了正規表達式來處理,具體怎麼實作不是很清楚。

對于大多數情況來說運作最耗時間的就是比對問題,類型,以及協定資訊可以根據url分析出來,很容易分離,

是以這裡重點介紹如何實作最核心的*,^的比對,通過一個patternStep來減小嵌套次數

/*

  get a much bigger step for *.

  */

static inline

int  patternStep( const char * s,

const  char * p)

{

    //這裡可以根據下一個字元多跳幾個

    char temp[8];

    int step=0;

    const char * t=p;

    while(*t!='*' && *t!='^' &&

*t!='\0')

    {

        step++;

        t++;

    }

    if(!step) //防止隻有一個通配符的情況比如^,*

        return 1;

    memset(temp,0,sizeof(temp));

    strncpy(temp,p,min(sizeof(temp)-1,step));

printf("temp=%s,step=%d\n",temp,step);

    const char * res=strfind(s,temp);

    if(!res) //沒有找到

        return strlen(s); //移動真整個字元串

    else

        return max(1,res-s); //找到第一個比對的字元串的位置

}

   test if a given string  and a pattern 

matches use adblock plus rule

   give a string s and a pattern p ,

   if they match,return 1, then return 0

   */

bool adbMatch(const

char *  s,  const char * 

p,bool caseSensitivie=true) {

    for (;;) {

        switch(*p++) {

            case '*' :  // match 0-n of any characters

                //這裡可以根據下一個字元多跳幾個

                if (!*p) return true; // do

trailing * quickly

                while (!adbMatch(s,

p,caseSensitivie))

                {

                    if(!*s) return false;

                    s+=patternStep(s,p);

                }

                return true;

            case '^':

                if(isSeperator(*s))

                    s++;

                    break;

                }

                else

                    return false;//expect a

sepetor,

            case '\0':  // end of pattern

                return !*s;

            default  :

                if

(getCaseChar(*s++,caseSensitivie) !=

getCaseChar(*(p-1),caseSensitivie)) return false;

                break;

        }

}

繼續閱讀