5.5 字串/陣列的比較

你可以使用這一節的函式來執行字串和陣列內容的比較,而且為了檢查字串的相等,這些函式也用做排序操作函式,見 Searching and Sorting,有一個例子。

不像C語言裡多數的比較運算,假如字串不相等,字串的比較函式會傳回非零值,這個表示值說明不相同的字串裡第一個字元的相對順序:負值表示第一個字串”小於”第二個字串,而正值表示第一個字串是 “較大的”。

最常使用的函式只是檢查相等,照規範使用這樣的表示式 ‘! strcmp (s1, s2)’。

這些函式都宣告在標頭檔 string.h中。

— 函式: int memcmp (const void *a1, const void *a2, size_t size)

函式 memcmp 比較 a1 跟 a2 記憶體前面 size 個位元組,傳回值跟第一對不同的字元的差異有相同的符號(以unsigned char 物件表示,然後轉成 int)。

假如這兩個記憶體內容相同時, memcmp 傳回0。

— 函式: int wmemcmp (const wchar_t *a1, const wchar_t *a2, size_t size)

函式 wmemcmp 比較 a1 跟 a2 前面 size 個寬字元,傳回值小於零或大於零取決於 a1 第一個不同的寬字元小於或大於相對應的 a2 字元。

假如這兩個記憶體內容相同時, wmemcmp 傳回0。

對任意陣列來說, memcmp 函式在測試相等時相當有用,在陣列的內容上以逐字元順序而非位元組做比較通常比較沒有意義,例如,在以浮點數組成的位元組做逐字元的比較是不太可能告訴你你任何關於浮點數的值之間的關係。

wmemcmp 真的只有在型態 wchar_t 的陣列比較才有用,因為函式一次以 sizeof (wchar_t) 位元組來檢查,而位元組的數目取決於作業系統。

你也應該小心使用 memcmp 來比較含有“holes”的物件,像是新增到結構物件的不明確位置的區塊(padding)、在同構(unions)結尾的空間,以及長度小於配置的大小時的字串結尾多餘的字元,這些 “holes” 的內容是不確定的,而且在執行逐位元比較時會有奇怪的狀況發生,為了得到可預期的結果,執行明確的組件比較。

例如,給定一個結構型態定義像:

     struct foo
       {
         unsigned char tag;
         union
           {
             double f;
             long i;
             char *p;
           } value;
       };

你最好寫一個特製的比較函式來比較 struct foo 物件而不是用 memcmp 來比較他們。

— 函式: int strcmp (const char *s1, const char *s2)

strcmp 函式比較字串 s1 跟 s2,傳回一個跟第一對不同字元差異的符號值(以 unsigned char 物件表示,然後轉成 int)。

假如兩個字串相同,strcmp 傳回0。

使用 strcmp 排序的結果就是假如 s1 原來是 s2一部分的字串,那麼 s1 會被認為 “小於” s2

strcmp 不會考慮字串被寫入的語言排序規範,要那樣做必須使用 strcoll。

— 函式: int wcscmp (const wchar_t *ws1, const wchar_t *ws2)

wcscmp 函式比較寬字元字串 ws1 跟 ws2,傳回值小於或大於零取決於第一個不同的寬字元是 ws1 小於或大於相對應的 ws2 字元。

假如兩個字串相同, wcscmp 傳回0。

使用 wcscmp 排序的結果就是假如 ws1 原來是 ws2 一部分的字串,那麼 ws1 會被認為 “小於” ws2

wcscmp 不會考慮字串被寫入的語言排序規範,要那樣做必須使用 wcscoll。

— 函式: int strcasecmp (const char *s1, const char *s2)

這函式像 strcmp,除了大小寫會忽略外,大小寫字元的關係如何由目前選擇的語系決定,在標準的 "C" 語系中字元 Ä 跟 ä 不一樣,但是在把這些字元當成是字母的一部份的語系裡,他們是一樣的。

strcasecmp 是從 BSD 衍生出來的。

— 函式: int wcscasecmp (const wchar_t *ws1, const wchar_t *ws2)

這函式像 wcscmp,除了大小寫的差異會忽略外,大小寫字元的關係如何由目前選擇的語系來決定,在標準的 "C" 語系中字元 Ä 和 ä 不一樣,但是在把這些字元當成是字母的一部份的語系裡,他們是一樣的。

wcscasecmp 是 GNU 的擴充函式。

— 函式: int strncmp (const char *s1, const char *s2, size_t size)

這函式類似 strcmp,除了不超過 size 個的字元被比較之外,換句話說,假如兩個字串前面 size 個字元是一樣的話,傳回值是零。

— 函式: int wcsncmp (const wchar_t *ws1, const wchar_t *ws2, size_t size)

這函式類似 wcscmp,除了不超過 size 個的寬字元比較之外,換句話說,假如兩個字串前面 size 個寬字元是一樣的話,傳回值是零。

— 函式: int strncasecmp (const char *s1, const char *s2, size_t n)

這函式像 strncmp,除了大小寫會被忽略之外,像 strcasecmp,它也是取決於語系來決定大小寫字元的關係。

strncasecmp 是 GNU 的擴充函式。

— 函式: int wcsncasecmp (const wchar_t *ws1, const wchar_t *s2, size_t n)

這函式像 wcsncmp,除了大小寫會被忽略之外,像 wcscasecmp,它也是取決於語系來決定大小寫字元的關係。

wcsncasecmp 是 GNU 的擴充函式。

這裡有一些例子顯示 strcmp 和 strncmp的使用(相同的例子可以建構於寬字元的函式)這些範例假設使用 ASCII 字元集,(假如改用其他的字元集–如 EBCDIC,那麼字型會有不同數值碼,傳回的值跟順序也會不同。)

     strcmp ("hello", "hello")
         ⇒ 0    /* These two strings are the same. */
     strcmp ("hello", "Hello")
         ⇒ 32   /* Comparisons are case-sensitive. */
     strcmp ("hello", "world")
         ⇒ -15  /* The character 'h' comes before 'w'. */
     strcmp ("hello", "hello, world")
         ⇒ -44  /* Comparing a null character against a comma. */
     strncmp ("hello", "hello, world", 5)
         ⇒ 0    /* The initial 5 characters are the same. */
     strncmp ("hello, world", "hello, stupid world!!!", 5)
         ⇒ 0    /* The initial 5 characters are the same. */

— 函式: int strverscmp (const char *s1, const char *s2)

strverscmp 函式比較字串 s1 跟 s2,但會考慮裡面的索引/版本數字,傳回值有跟 strcmp 函式一樣的規範,事實上假如s1 和 s2 沒有數字, strverscmp 就像 strcmp一樣。

基本上我們通常比較字串(逐字元),直到我們在字串裡發現數字 – 接著我們進入一個特殊比較模式,在這裡每個數字序列看成是一個數目,假如我們到達這兩個部份的最後沒有注意到差異,我們就會返回標準的比較模式,有兩種數值型態的部份:”整數的” 跟 “零數的” (以 ‘0’開始的數字),數值部份的型態會影響到我們排序它們的方式:

  • 整數的/整數的:我們會如你預期的方式比較值。
  • 零數的/整數的:零數的部份比整數的部份小,這也是我預期的。
  • 零數的/零數的:這件事會變得有點複雜,如果常見的前綴只有零,最長的部份小於另一個;否則比較會是正常的。
          strverscmp ("no digit", "no digit")
              ⇒ 0    /* same behavior as strcmp. */
          strverscmp ("item#99", "item#100")
              ⇒ <0   /* same prefix, but 99 < 100. */
          strverscmp ("alpha1", "alpha001")
              ⇒ >0   /* fractional part inferior to integral one. */
          strverscmp ("part1_f012", "part1_f01")
              ⇒ >0   /* two fractional parts. */
          strverscmp ("foo.009", "foo.0")
              ⇒ <0   /* idem, but with leading zeroes only. */

這函式在處理檔案名稱的排序時特別有用,因為檔案名稱通常會有索引/版本數。

strverscmp 是 GNU 的擴充函式。

— 函式: int bcmp (const void *a1, const void *a2, size_t size)

這函式是 memcmp 過時的別名, 是從 BSD 衍生出來的。

下一節: ,上一節: Copying and Concatenation,這一章:字串和陣列的工具

感謝你看到這裡,很快就可以離開了,但最好的獎勵行動就是按一下幫我分享或留言,感恩喔~

點我分享到Facebook

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *