字串查詢函數,C語言字串查詢函數詳解

2020-07-16 10:04:26
在對 C 語言的程式設計實踐中,字串查詢是最頻繁的字串操作之一,本節就對常用的字串查詢函數做一個簡單的總結。

使用 strchr 與 strrchr 函數查詢單個字元

如果需要對字串中的單個字元進行查詢,那麼應該使用 strchr 或 strrchr 函數。其中,strchr 函數原型的一般格式如下:

char *strchr(const char *s, int c);

它表示在字串 s 中查詢字元 c,返回字元 c 第一次在字串 s 中出現的位置,如果未找到字元 c,則返回 NULL。也就是說,strchr 函數在字串 s 中從前到後(或者稱為從左到右)查詢字元 c,找到字元 c 第一次出現的位置就返回,返回值指向這個位置,如果找不到字元 c 就返回 NULL。

相對於 strchr 函數,strrchr 函數原型的一般格式如下:

char *strrchr(const char *s, int c);

與 strchr 函數一樣,它同樣表示在字串 s 中查詢字元 c,返回字元 c 第一次在字串 s 中出現的位置,如果未找到字元 c,則返回 NULL。但兩者唯一不同的是,strrchr 函數在字串 s 中是從後到前(或者稱為從右向左)查詢字元 c,找到字元 c 第一次出現的位置就返回,返回值指向這個位置。下面的範例程式碼演示了兩者之間的區別:
int main(void)
{
    char str[] = "I welcome any ideas from readers, of course.";
    char *lc = strchr(str, 'o');
    printf("strchr: %sn", lc);
    char *rc = strrchr(str, 'o');
    printf("strrchr: %sn", rc);
    return 0;
}
對於上面的範例程式碼,strchr 函數是按照從前到後的順序進行查詢,所以得到的結果為“ome any ideas from readers,of course.”; 而 strrchr 函數則相反,它按照從後到前的順序進行查詢,所以得到的結果為“ourse.”。

範例程式碼執行結果為:
strchr: ome any ideas from readers, of course.
strrchr: ourse.

最後還需要注意的是,為什麼函數的“c”引數是 int 型別,而不是“char”型別呢?

其實原因很簡單,這裡用的是字元的 ASCII 碼(因為每個字元都對應著一個 ASCII 碼),這樣在傳值的時候既可以傳“char”型別的值,又可以傳“int”型別的值(0~127)。

使用 strpbrk 函數查詢多個字元

上面的 strchr 與 strrchr 函數解決了對字串中單個字元的查詢,那麼需要查詢多個字元時怎麼辦呢?

如果要查詢多個字元,就需要使用 strpbrk 函數了。該函數在源字串(s1)中按從前到後順序找出最先含有搜尋字串(s2)中任一字元的位置並返回,空字元 null('') 不包括在內,若找不到則返回空指標。其函數原型的一般格式如下:

char *strpbrk(const char *s1,const char *s2);

例如,在 strpbrk 函數的定義如下:
char *strpbrk (const char *s, const char *accept)
{
    while (*s != '')
    {
        const char *a = accept;
        while (*a != '')
            if (*a++ == *s)
                return (char *) s;
        ++s;
    }
    return NULL;
}
如上面的程式碼所示,strpbrk 數首先依次迴圈檢查字串 s 中的字元,當被檢驗的字元在字串 accept 中也包含時(即“if(*a++==*s)”),則停止檢驗,並返回“(char*)s”。如果沒有匹配字元,則返回空指標 NULL。這裡需要注意的是,空字元 null('')不包括在內。函數的呼叫範例如下面的程式碼所示:
int main(void)
{
    char str[] = "I welcome any ideas from readers, of course.";
    char *rc=strpbrk(str,"come");
    printf("%sn",rc);
    return 0;
}
很顯然,範例程式碼的執行結果為“elcome any ideas from readers,of course.”。

使用 strstr 函數查詢一個子串

相對於 strpbrk 函數,strstr 函數表示在字串 haystack 中從前到後查詢子串 needle 第一次出現的位置(不比較結束符 null('')),並返回指向第一次出現 needle 位置的指標,如果沒找到則返回 NULL。其函數原型的一般格式如下:

char *strstr(const char *haystack, const char *needle);

strstr 函數的呼叫範例如下面的程式碼所示:
int main(void)
{
    char str[] = "I welcome any ideas from readers, of course.";
    char *c1=strstr(str, "come");
    printf("come:%sn",c1);
    char *c2=strstr(str, "icome");
    printf("icome:%sn",c2);
    return 0;
}
這裡需要注意的是,因為 strstr 函數與 strpbrk 函數不同,strstr 函數匹配的是字串,所以語句“strstr(str,"icome")”將返回 NULL。執行結果為:
come:come any ideas from readers, of course.
icome:(null)

區別 strspn 與 strcspn 函數

strspn 函數表示從字串 s 的第一個字元開始,逐個檢查字元與字串 accept 中的字元是否不相同,如果不相同,則停止檢查,並返回以字串 s 開頭連續包含字串 accept 內的字元數目。其函數原型的一般格式如下:

size_t strspn(const char *s, const char *accept);

例如,該函數的定義如下:
size_t strspn (const char *s,const char *accept)
{
    const char *p;
    const char *a;
    size_t count = 0;
    for (p = s; *p != ''; ++p)
    {
        for (a = accept; *a != ''; ++a)
            if (*p == *a)
                break;
            if (*a == '')
                return count;
            else
                ++count;
    }
    return count;
}
從上面的範例程式碼中可以看出,strspn 函數從字串引數 s 的開頭計算連續的字元,而這些字元完全是 accept 所指字串中的字元。簡單地說,如果 strspn 函數返回的數值為 n,則代表字串 s 開頭連續有 n 個字元都屬於字串 accept 內的字元。

函數的呼叫範例如下面的程式碼所示:
int main(void)
{
    char str[] = "I welcome any ideas from readers, of course.";
    printf("I wel:%dn",strspn(str,"I wel"));
    printf("Iwel:%dn",strspn(str,"Iwel"));
    printf("welcome:%dn",strspn(str,"welcome"));
    printf("5:%dn",strspn(str,"5"));
    return 0;
}
在上面的範例程式碼中,因為 strspn 函數返回的是以字串 s 開頭連續包含字串 accept 內的字元數目。而源字串 str 中的“I”與“welcome”之間有一個空格(即“I welcome”),所以,語句“strspn(str,"Iwel")”將返回 1,而語句“strspn(str,"I wel")”將返回 5。因此,輸出結果為:
I wel:5
Iwel:1
welcome:0
5:0

相對於 strspn 函數,strcspn 函數與之相反,它表示從字串 s 第一個字元開始,逐個檢查字元與 reject 中的字元是否相同,如果相同,則停止檢查,並返回以字串 s 開頭連續不含字串 reject 內的字元數目。其函數原型的一般格式如下:

size_t strcspn(const char *s, const char *reject);

該函數的定義如下:
size_t strcspn (const char *s,const char *reject)
{
    size_t count = 0;
    while (*s != '')
        if (strchr (reject, *s++) == NULL)
            ++count;
        else
            return count;
    return count;
}
從上面的程式碼中不難發現,strcspn 函數正好與 strspn 函數相反。strcspn 函數從字串引數 s 的開頭計算連續的字元,而這些字元都完全不在引數 reject 所指的字串中。簡單地說,如果 strcspn 函數返回的數值為 n,則代表字串 s 開頭連續有 n 個字元都不包含字串 reject 內的字元。

函數的呼叫範例如下面的程式碼所示:
int main(void)
{
    char str[] = "I welcome any ideas from readers, of course.";
    printf("I wel:%dn",strcspn(str,"I wel"));
    printf("Iwel:%dn",strcspn(str,"Iwel"));
    printf("welcome:%dn",strcspn(str,"welcome"));
    printf("5:%dn",strcspn(str,"5"));
    return 0;
}
在上面的範例程式碼中,因為 strcspn 函數返回的是以字串 s 開頭連續不包含字串 accept 內的字元數目。因此,其執行結果為:
I wel:0
Iwel:0
welcome:2
5:45

由此可見,對於 strspn 函數,如果找到了 reject 與 s 不相同元素時,指標停止移動,並返回以字串 s 開頭連續包含字串 accept 內的字元數目;而 strncspn 函數則是找到了 reject 與 s 相同元素時,指標停止移動,並返回以字串 s 開頭連續不包含字串 accept 內的字元數目。這一點一定要注意,千萬不要混淆了。