Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C++

เขียน strcmp() เองที่ไม่สนใจ Case (Case-Insensitive) ใน C++

โจทย์

สร้างฟังก์ชันเปรียบเทียบสตริง (strcmp) ที่ ไม่สนใจพิมพ์เล็ก/พิมพ์ใหญ่ (case-insensitive)

คืนค่า: -1 หาก str1 < str2, 0 หาก str1 == str2, 1 หาก str1 > str2

ตัวอย่าง

Input: "Hello", "hello"
Output: 0 (เหมือนกันเมื่อไม่สนใจ case)

อัลกอริทึม

  1. วนลูปเปรียบเทียบตัวอักษรทีละคู่
  2. แปลงทั้งคู่ให้เป็นตัวพิมพ์เล็ก (หรือใหญ่) ก่อนเปรียบเทียบ
  3. หากต่างกัน คืนค่า -1 หรือ 1 ตามลำดับ ASCII
  4. หากจบสตริงพร้อมกัน คืนค่า 0

โค้ดตัวอย่าง

#include <iostream>
#include <cctype>  // for tolower
using namespace std;

int strcmpIgnoreCase(const char* str1, const char* str2) {
    while (*str1 && *str2) {
        char c1 = tolower(static_cast<unsigned char>(*str1));
        char c2 = tolower(static_cast<unsigned char>(*str2));
        
        if (c1 != c2) {
            return (c1 < c2) ? -1 : 1;
        }
        str1++;
        str2++;
    }
    
    // หนึ่งสตริงจบ ก่อนอีกตัว
    if (*str1 == '\0' && *str2 == '\0') return 0;
    return (*str1 == '\0') ? -1 : 1;
}

// Overload สำหรับ std::string
int strcmpIgnoreCase(const string& s1, const string& s2) {
    size_t n = min(s1.size(), s2.size());
    for (size_t i = 0; i < n; i++) {
        char c1 = tolower(static_cast<unsigned char>(s1[i]));
        char c2 = tolower(static_cast<unsigned char>(s2[i]));
        if (c1 != c2) return (c1 < c2) ? -1 : 1;
    }
    if (s1.size() == s2.size()) return 0;
    return (s1.size() < s2.size()) ? -1 : 1;
}

int main() {
    cout << "Case-insensitive strcmp results:\n";
    cout << "HELLO vs hello: " << strcmpIgnoreCase("HELLO", "hello") << endl;
    cout << "empty vs Hello: " << strcmpIgnoreCase("", "Hello") << endl;
    cout << "Tutorials vs Pint: " << strcmpIgnoreCase("Tutorials", "Pint") << endl;
    cout << "afdadsa vs rewf: " << strcmpIgnoreCase("afdadsa", "rewf") << endl;
    cout << "tutorialspoint vs TUTORIALSpoint: " << strcmpIgnoreCase("tutorialspoint", "TUTORIALSpoint") << endl;
    return 0;
}

ผลลัพธ์

Case-insensitive strcmp results:
HELLO vs hello: 0
empty vs Hello: -1
Tutorials vs Pint: 1
afdadsa vs rewf: -1
tutorialspoint vs TUTORIALSpoint: 0

เทคนิค Bitwise Trick (ASCII Only)

ใน ASCII: ตัวพิมพ์ใหญ่ (A-Z: 65-90) และตัวพิมพ์เล็ก (a-z: 97-122) ต่างกันที่ bit 5 (ค่า 32)

// 'A' (01000001) ^ 32 = 'a' (01100001)
// 'a' (01100001) ^ 32 = 'A' (01000001)

char toLowerASCII(char c) {
    return (c >= 'A' && c <= 'Z') ? (c | 32) : c;  // set bit 5
}

// หรือ
char toUpperASCII(char c) {
    return (c >= 'a' && c <= 'z') ? (c & ~32) : c;  // clear bit 5
}

C++ Standard Library Alternatives

#include <algorithm>
#include <cctype>
#include <string>

// 1. strcasecmp (POSIX, not standard C++)
// int result = strcasecmp(str1, str2);

// 2. Custom comparator with std::lexicographical_compare
bool caseInsensitiveLess(const string& a, const string& b) {
    return lexicographical_compare(a.begin(), a.end(), b.begin(), b.end(),
        [](char c1, char c2) { return tolower(c1) < tolower(c2); });
}

// 3. Boost (if available)
// boost::algorithm::ilexicographical_compare

Complexity

  • Time: O(min(len1, len2))
  • Space: O(1)

สรุป

Case-insensitive string comparison ต้องใช้ tolower() หรือ toupper() จาก <cctype> พร้อม cast เป็น unsigned char เพื่อหลีกเลี่ยง undefined behavior กับค่าลบ บน ASCII สามารถใช้ bitwise trick (| 32) ได้ แต่ไม่ portable สำหรับ EBCDIC หรือ Unicode