HOWTO · C
C 語言中檢查字串是否包含子字串
本文演示瞭如何在 C 語言中檢查一個字串是否包含子字串。
本頁內容
若要檢查以 null 結尾的 C 字串是否包含完全相符且區分大小寫的子字串,請使用 <string.h> 中的 strstr。它會傳回第一個相符位置的指標;若找不到,則傳回 NULL。以下範例皆已執行,並輸出 Substring found.;此輸出標籤保留英文。
使用 strstr 檢查子字串
將完整字串作為第一個引數,將要搜尋的文字作為第二個引數。直接檢查傳回的指標;不要將它當成位址印出,因為位址會依執行程序而異。標準 C 標頭 <string.h> 宣告了 strstr,它會逐字元比對,並區分大小寫。
以下程式會在句子中搜尋 welcome,並輸出固定且明確的找到或找不到訊息。
#include <stdio.h>
#include <string.h>
int main(void) {
const char *text = "Hello, welcome to C.";
const char *needle = "welcome";
if (strstr(text, needle) != NULL) {
puts("Substring found.");
} else {
puts("Substring not found.");
}
return 0;
}
Substring found.
傳回的指標會指向 text 中第一個相符字元,因此你可以用它檢查該位置,或從該處繼續搜尋。指標不為 null 就表示找到相符內容。若搜尋文字是 "",strstr 會傳回 text 的起始位置;如果你的應用程式不應將空搜尋文字視為相符,請留意這項標準行為並另行處理。
使用迴圈搜尋子字串
手動搜尋能清楚呈現比對過程,也能讓你加入應用程式專用的行為。下方函式接收兩個非 null、以 null 結尾的字串;搜尋文字出現時回傳 1,否則回傳 0。它會先檢查長度再進行相減,避免搜尋文字比輸入字串長時發生無號整數下溢。若搜尋文字為空,它會視為相符,與 strstr 的行為一致。
#include <stdio.h>
#include <string.h>
int contains_substring(const char *text, const char *needle) {
size_t text_len = strlen(text);
size_t needle_len = strlen(needle);
if (needle_len == 0) {
return 1;
}
if (needle_len > text_len) {
return 0;
}
for (size_t i = 0; i <= text_len - needle_len; ++i) {
size_t j = 0;
while (j < needle_len && text[i + j] == needle[j]) {
++j;
}
if (j == needle_len) {
return 1;
}
}
return 0;
}
int main(void) {
const char *text = "Hello, welcome to C.";
const char *needle = "welcome";
puts(contains_substring(text, needle)
? "Substring found."
: "Substring not found.");
return 0;
}
Substring found.
外層迴圈會逐一嘗試所有能容納完整搜尋文字的起始位置。內層迴圈只會在對應字元相符時繼續前進。若它走到搜尋文字的長度,就表示函式已找到完整相符內容。這種直觀的方法適合教學或自訂需求;一般的精確比對則建議使用標準函式庫函式,除非你有理由自行維護搜尋程式碼。
檢查不區分大小寫的子字串
C 標準函式庫沒有定義不區分大小寫的子字串搜尋函式。在 GNU 系統上,strcasestr 會忽略大小寫搜尋,並以 GNU 擴充功能提供。在使用此功能測試巨集的系統上,請在引入標頭檔之前定義 _GNU_SOURCE,以要求宣告此函式。它不是可攜式的標準 C 函式,因此使用前請確認目標平台有提供。
以下完整範例使用 ASCII 文字,示範 GNU 專用的呼叫方式;輸出標籤 Substring found. 保留英文。
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
int main(void) {
const char *text = "Hello, Welcome to C.";
const char *needle = "welcome";
if (strcasestr(text, needle) != NULL) {
puts("Substring found.");
} else {
puts("Substring not found.");
}
return 0;
}
Substring found.
若要撰寫可攜式程式碼,請先明確訂定字元處理規則,再自行實作不區分大小寫的比對,而不要默默修改輸入字串。tolower 可用於以位元組為單位的文字,但其引數必須是 EOF,或可表示為 unsigned char 的值;其行為也會依目前的 C 地區設定而定。這種作法本身不會提供 Unicode 大小寫折疊。請依程式需要處理的資料選擇合適的函式庫與文字規則。
處理邊界情況並選擇方法
strstr 和上方的迴圈都會搜尋以 null 結尾的字串,並比對完全相同的字元序列。若搜尋文字比輸入文字長,就不可能相符。若搜尋文字為空,strstr 會回報在起始位置找到;上方的迴圈實作也採用相同慣例。若你的應用程式需要不同規則,請明確檢查空字串。此迴圈要求指標不為 null;和標準字串函式一樣,傳入的引數必須是有效字串。
strstr 會傳回第一個相符位置。若要尋找後續位置,可以從前一次相符位置加上搜尋文字長度之處繼續搜尋;但必須確認搜尋文字非空,才能讓下一次搜尋向前推進。若需要找出重疊的相符內容,則從前一次相符位置往後一個字元處繼續搜尋。該如何選擇,取決於你是否允許相符內容共用字元。
一般的精確、區分大小寫檢查請使用 strstr:它簡潔,而且屬於標準 C。若要教學或自訂比對方式,可以使用手動迴圈,並記錄它對輸入的假設。只有在 GNU 擴充功能可用,且其位元組與地區設定行為適用於你的文字時,才使用 strcasestr。strpbrk 不能用來精確搜尋子字串:它檢查的是輸入中是否出現某個字元集合裡的任一字元,回答的是另一個問題。