PHP7 內(nèi)核源碼 strstr 查找字符串: Sunday 字符串匹配超快算法

strstr

返回 haystack 字符串從 needle 第一次出現(xiàn)的位置開始到 haystack 結(jié)尾的字符串艺栈。
strstr( string $haystack, mixed $needle[, bool $before_needle = FALSE] ) : string

源碼實現(xiàn)

/* {{{ proto string strstr(string haystack, string needle[, bool part])
   Finds first occurrence of a string within another */
PHP_FUNCTION(strstr)
{
    zval *needle;
    zend_string *haystack;
    const char *found = NULL;
    char needle_char[2];
    zend_long found_offset;
    zend_bool part = 0;

    ZEND_PARSE_PARAMETERS_START(2, 3)
        Z_PARAM_STR(haystack)
        Z_PARAM_ZVAL(needle)
        Z_PARAM_OPTIONAL
        Z_PARAM_BOOL(part)
    ZEND_PARSE_PARAMETERS_END();

    if (Z_TYPE_P(needle) == IS_STRING) { 
        if (!Z_STRLEN_P(needle)) {
            php_error_docref(NULL, E_WARNING, "Empty needle");
            RETURN_FALSE;
        }

        found = php_memnstr(ZSTR_VAL(haystack), Z_STRVAL_P(needle), Z_STRLEN_P(needle), ZSTR_VAL(haystack) + ZSTR_LEN(haystack));
    } else {
        //如果 needle 不是一個字符串湿右,那么它將被轉(zhuǎn)化為整型并且作為字符的序號來使用毅人。
        if (php_needle_char(needle, needle_char) != SUCCESS) {
            RETURN_FALSE;
        }
        needle_char[1] = 0;

        php_error_docref(NULL, E_DEPRECATED,
            "Non-string needles will be interpreted as strings in the future. " \
            "Use an explicit chr() call to preserve the current behavior");

        found = php_memnstr(ZSTR_VAL(haystack), needle_char, 1, ZSTR_VAL(haystack) + ZSTR_LEN(haystack));
    }

    if (found) {
        found_offset = found - ZSTR_VAL(haystack);
        if (part) {
            RETURN_STRINGL(ZSTR_VAL(haystack), found_offset);
        } else {
            RETURN_STRINGL(found, ZSTR_LEN(haystack) - found_offset);
        }
    }
    RETURN_FALSE;
}
/* }}} */

核心算法實現(xiàn)追蹤 php.h 文件: php_memnstr

#define php_memnstr zend_memnstr

追蹤 zend_operators.h : zend_memnstr

static zend_always_inline const char *
zend_memnstr(const char *haystack, const char *needle, size_t needle_len, const char *end)
{
    const char *p = haystack;
    const char ne = needle[needle_len-1];
    ptrdiff_t off_p;
    size_t off_s;

    if (needle_len == 1) {
        return (const char *)memchr(p, *needle, (end-p));
    }

    off_p = end - haystack;
    off_s = (off_p > 0) ? (size_t)off_p : 0;

    if (needle_len > off_s) {
        return NULL;
    }
    //當(dāng)輸入的字符串小于 1024字符或查找字符串長度小于9 的時候吭狡,使用系統(tǒng)庫 glibc  memchr 查找
    if (EXPECTED(off_s < 1024 || needle_len < 9)) { /* glibc memchr is faster when needle is too short */
        end -= needle_len;

        while (p <= end) {
            if ((p = (const char *)memchr(p, *needle, (end-p+1))) && ne == p[needle_len-1]) {
                if (!memcmp(needle+1, p+1, needle_len-2)) {
                    return p;
                }
            }

            if (p == NULL) {
                return NULL;
            }

            p++;
        }

        return NULL;
    } else {
        //使用 Sunday 算法查找
        return zend_memnstr_ex(haystack, needle, needle_len, end);
    }
}

zend_memnstr_ex 實現(xiàn)

ZEND_API const char* ZEND_FASTCALL zend_memnstr_ex(const char *haystack, const char *needle, size_t needle_len, const char *end) /* {{{ */
{
    unsigned int td[256];
    register size_t i;
    register const char *p;

    if (needle_len == 0 || (end - haystack) < needle_len) {
        return NULL;
    }
    //前綴表
    zend_memnstr_ex_pre(td, needle, needle_len, 0);

    p = haystack;
    end -= needle_len;

    while (p <= end) {
        for (i = 0; i < needle_len; i++) {
            if (needle[i] != p[i]) {
                break;
            }
        }
        if (i == needle_len) {
            return p;
        }
        if (UNEXPECTED(p == end)) {
            return NULL;
        }
        p += td[(unsigned char)(p[needle_len])];
    }

    return NULL;
}
/* }}} */

zend_memnstr_ex_pre 實現(xiàn) (Sunday 字符串匹配算法划煮,速度最快的字符串匹配算法,)

  • 如果字母表與模式的長度相比較大场刑,則算法平均執(zhí)行O(n / m)比較
/*
 * String matching - Sunday algorithm
 * http://www.iti.fh-flensburg.de/lang/algorithmen/pattern/sundayen.htm
 */
static zend_always_inline void zend_memnstr_ex_pre(unsigned int td[], const char *needle, size_t needle_len, int reverse) /* {{{ */ {
    int i;
    //生成256字符表
    for (i = 0; i < 256; i++) {
        td[i] = needle_len + 1;
    }

    if (reverse) {
        for (i = needle_len - 1; i >= 0; i--){
            // 整型 [ ASCII 碼] => X
            td[(unsigned char)needle[i]] = i + 1;
        }
    } else {
        size_t i;

        for (i = 0; i < needle_len; i++) {
            td[(unsigned char)needle[i]] = (int)needle_len - i;
        }
    }
}
/* }}} */

字符串匹配算法——Sunday(PHP實現(xiàn))

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蚪战,一起剝皮案震驚了整個濱河市牵现,隨后出現(xiàn)的幾起案子铐懊,更是在濱河造成了極大的恐慌,老刑警劉巖科乎,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茅茂,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門掉丽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人僧须,你說我怎么就攤上這事项炼〉F剑” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵锭部,是天一觀的道長驱闷。 經(jīng)常有香客問我,道長空免,這世上最難降的妖魔是什么空另? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮蹋砚,結(jié)果婚禮上扼菠,老公的妹妹穿的比我還像新娘。我一直安慰自己坝咐,他們只是感情好循榆,可當(dāng)我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著墨坚,像睡著了一般秧饮。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天盗尸,我揣著相機與錄音柑船,去河邊找鬼。 笑死泼各,一個胖子當(dāng)著我的面吹牛鞍时,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播扣蜻,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼逆巍,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了莽使?” 一聲冷哼從身側(cè)響起锐极,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎芳肌,沒想到半個月后灵再,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡庇勃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年檬嘀,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片责嚷。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡鸳兽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出罕拂,到底是詐尸還是另有隱情揍异,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布爆班,位于F島的核電站衷掷,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏柿菩。R本人自食惡果不足惜戚嗅,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望枢舶。 院中可真熱鬧懦胞,春花似錦、人聲如沸凉泄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽后众。三九已至胀糜,卻和暖如春颅拦,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背教藻。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工距帅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人怖竭。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓锥债,卻偏偏與公主長得像陡蝇,于是被迫代替她去往敵國和親痊臭。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 還有九天就要上戰(zhàn)場了登夫。第一次真正的參加注會考試广匙,認(rèn)真的準(zhǔn)備著。一直相信夠努力才可能會有好運氣恼策。不知道結(jié)果如何鸦致,可無...
    大夢想家小小閱讀 205評論 0 0
  • 我:哇~混血兒好可愛,我也想生個混血兒~ 他:其實我是XX星球派來拯救地球的涣楷!我有個變身器放在我的背包里分唾,一遇到緊...
    喜歡小u閱讀 80評論 0 0
  • 很久沒有到公園散步了。 于是狮斗,在這個風(fēng)和日麗的周末绽乔,我?guī)е⒆右黄饋砉珗@賞花。 石家莊的冬季甚是漫長碳褒,春天卻是神龍...
    卯金金閱讀 244評論 0 2