Strcasecmp algoritması hatalı mı?


34

strcasecmpC fonksiyonu yeniden uygulamaya çalışıyorum ve karşılaştırma sürecinde bir tutarsızlık gibi görünüyor fark ettim.

itibaren man strcmp

Strcmp () işlevi, iki s1 ve s2 dizesini karşılaştırır. Yerel ayar dikkate alınmaz (yerel ayarlara duyarlı bir karşılaştırma için bkz. Strcoll (3)). Eğer s1 sırasıyla, eşleşecek, eşleşecek veya s2'den büyük olacaksa, sıfırdan küçük, ona eşit veya sıfırdan büyük bir tamsayı döndürür.

itibaren man strcasecmp

Strcasecmp () işlevi, karakterlerin durumunu göz ardı ederek s1 ve s2 dizelerinin bayt bayt karşılaştırmasını gerçekleştirir. Eğer s1 sırasıyla, eşleşecek, eşleşecek veya s2'den büyük olacaksa, sıfırdan küçük, ona eşit veya sıfırdan büyük bir tamsayı döndürür.

int strcmp(const char *s1, const char *s2);
int strcasecmp(const char *s1, const char *s2);

Verilen bu bilgi, aşağıdaki kodun sonucunu anlamıyorum:

#include <stdio.h>
#include <string.h>

int main()
{
    // ASCII values
    // 'A' = 65
    // '_' = 95
    // 'a' = 97

    printf("%i\n", strcmp("A", "_"));
    printf("%i\n", strcmp("a", "_"));
    printf("%i\n", strcasecmp("A", "_"));
    printf("%i\n", strcasecmp("a", "_"));
    return 0;
}

Çıkışı:

-1  # "A" is less than "_"
1   # "a" is more than "_"
2   # "A" is more than "_" with strcasecmp ???
2   # "a" is more than "_" with strcasecmp

Geçerli karakter s1bir harfse, geçerli karakterin s2bir harf olup olmadığına bakılmaksızın her zaman küçük harfe dönüştürülür .

Birisi bu davranışı açıklayabilir mi? Birinci ve üçüncü satırlar aynı olmamalı mı?

Şimdiden teşekkür ederim!

PS: Manjaro
kullanıyorum gcc 9.2.0.
Ayrıca, ben -fno-builtinbayrağı ile derlemek yerine:

-30
2
2
2

Sanırım bunun nedeni programın gcc'nin optimize edilmiş fonksiyonlarını kullanmaması, ancak soru kalmasıdır.


2
Sizin kümesine başka bir test durumda ekleyin: printf("%i\n", strcasecmp("a", "_"));Bu muhtemelen aynı sonucu olmalıdır printf("%i\n", strcasecmp("A", "_"));Ama bu demek istediğini bir bu iki harf duyarsız aramaların onun küçük harfe duyarlı meslektaşı katılmıyorum gidiyor.
anton.burger

strcasecmpBahsettiğiniz açıklama doğru değil. Yükseltilmiş cevaplarda daha fazla ayrıntı.
Jabberwocky

9
Mantıklı olan tek şey bu. Söyleyen bir işlev A < _ && a > _ && A == açok fazla soruna neden olur.
ikegami

Kenara: "C strcasecmp işlevini yeniden uygulamaya çalışıyorum" -> Kod gösterilmese de, "sanki" karşılaştırdığınızdan emin olun unsigned char. C17 / 18 "Dize kullanımı <string.h>" -> "Bu alt maddedeki tüm fonksiyonlar için, her karakter sanki türünde olarak yorumlanmalıdır unsigned char". charDeğerler ASCII 0-127 aralığının dışında olduğunda fark yaratır .
chux - Monica adlı kullanıcıdan

1
Yerleşik ve içermeyen çıkışlardaki farklarda: Her ikisi de aynı şeyi söyler, çünkü sonuçları aynı <0 ve> 0'dır ve == 0 için bir örneğiniz yoktur. Ancak algoritmaların parladığını görebilirsiniz: döndürülen değerlerden bazıları, eşit olmayan ilk karakterin farklılıklarıdır.
busybee

Yanıtlar:


31

Davranış doğrudur.

Başına POSIX str\[n\]casecmp()şartname :

Kullanılan LC_CTYPEyerel ayarın kategorisi POSIX yerel ayarından olduğunda, bu işlevler, dizeler küçük harfe dönüştürülmüş gibi davranır ve ardından bir bayt karşılaştırması gerçekleştirilir. Aksi takdirde sonuçlar belirtilmez.

Bu da bir parçası olan NOTLAR Linux kılavuz sayfasının bölümüne :

POSIX.1-2008 standardı şu işlevleri söylüyor:

Kullanılan yerel ayarın LC_CTYPE kategorisi POSIX yerel ayarından olduğunda, bu işlevler, dizeler küçük harfe dönüştürülmüş gibi davranır ve ardından bir bayt karşılaştırması gerçekleştirilir. Aksi takdirde sonuçlar belirtilmez.

Neden?

@HansOlsson'un cevabında belirttiği gibi , sadece harfler arasında büyük / küçük harfe duyarlı olmayan karşılaştırmalar yapmak ve diğer tüm karşılaştırmaların "doğal" sonuçlarının yapıldığı gibi yapılmasına izin strcmp()vermek sıralamayı bozacaktır.

Eğer 'A' == 'a'(küçük harf duyarlı bir karşılaştırma tanım) sonra '_' > 'A've '_' < 'a'(ASCII karakter setinde "doğal" sonuçlar) ikisi de doğru olamaz.


Yalnızca harfler arasında büyük / küçük harfe duyarlı olmayan karşılaştırmaların yapılması '_' > 'A' && '_' < 'a'; en iyi örnek gibi görünmüyor.
Kanatlı Asteroitler

1
@AsteroidsWithWings Soruda kullanılan karakterler. Ve eğer 'a' == 'A' tanım gereği size "doğal" değerleri arasında bir karşılaştırma yaparsak, 'a', 'A've '_' sen olamaz arasında bir harf duyarsız bir karşılaştırma yapmak 'A've 'a'eşitlik olsun ve tutarlı sıralama sonuçları almak için.
Andrew Henle

Buna itiraz etmiyorum, ancak sağladığınız belirli karşı örnek ilgili görünmüyor.
Kanatlı Asteroitler

Bir ikili ağacı oluşturmanın zihinsel egzersiz yoluyla @AsteroidsWithWings Git 'a', 'A've '_'sadece harf dönüştürmek" önerdi, ağacın içine yerleştirilmesi her 6 siparişleri geçmekte ve soru en belirtilen gibi "hep küçük harfli mektuplar" sonuçlarını karşılaştıran "bir harften harfe karşılaştırma". Örneğin, ikincisi algoritması kullanarak ve ile başlayan '_', 'a've 'A'ağacın karşı taraflarında rüzgar henüz eşit olarak tanımlanır ediyoruz. "Harfleri küçük harf karşılaştırmalarında sadece küçük harfe dönüştür" algoritması bozulur ve bu 3 karakter bunu gösterir.
Andrew Henle

Tamam, o zaman cevapta bunu göstermeyi öneriyorum çünkü şu anda bunun neden olabileceğini düşünmemiz gerektiğini söylemeden " '_' > 'A' ve '_' < 'a'her ikisi de doğru olamaz " diye işaret ediyor . (Bu milyonlarca okuyucudan biri için değil, cevaplayanlar için bir görevdir.)
Kanatlı Asteroitler

21

Diğer bağlantılar, http://man7.org/linux/man-pages/man3/strcasecmp.3p.html strcasecmp için küçük harfe dönüştürmenin doğru davranış olduğunu söylüyor (en azından POSIX yerel ayarında).

Bu davranışın nedeni, dizeleri sıralamak için strcasecmp kullanırsanız, makul sonuçlar almanız gerektiğidir.

Aksi takdirde, örneğin qsort kullanarak "A", "C", "_", "b" 'yi sıralamaya çalışırsanız, sonuç karşılaştırma sırasına bağlıdır.


3
Aksi takdirde, örneğin qsort kullanarak "A", "C", "_", "b" 'yi sıralamaya çalışırsanız, sonuç karşılaştırma sırasına bağlıdır. İyi bir nokta. POSIX'in davranışı belirtmesinin nedeni budur.
Andrew Henle

6
Daha somut olarak, karşılaştırmayı sorudaki gibi tanımlarsanız (geçişli olmayacağı için), sıralama için toplam bir siparişe ihtiyacınız vardır .
Dukeling

8

Görünüşe göre, s1'deki geçerli karakter bir harfse, s2'deki geçerli karakterin bir harf olup olmadığına bakılmaksızın her zaman küçük harfe dönüştürülür.

Bu doğru - ve strcasecmp()fonksiyonun yapması gereken bu! Bu, Standardın bir POSIXparçası olmaktan ziyade C, " Açık Grup Tabanı Spesifikasyonları, Sayı 6 " dan bir işlevdir :

POSIX yerel ayarında, strcasecmp () ve strncasecmp (), dizeler küçük harfe dönüştürülmüş gibi davranır ve ardından bir bayt karşılaştırması yapılır. Sonuçlar diğer bölgelerde belirtilmedi.

Bu arada, bu davranış _stricmp()işlev için de geçerlidir (Visual Studio / MSCV'de kullanıldığı gibi):

_Stricmp işlevi, her karakteri küçük harfe dönüştürdükten sonra string1 ve string2'yi sıralı olarak karşılaştırır ve ilişkilerini gösteren bir değer döndürür.


2

ASCII ondalık kodunu Aolduğu 65için _olduğu 95ve için aise 97bu yüzden, strcmp()bunu yapmak için varsayalım ne yapıyor. Sözlükbilimsel olarak konuşma _o zamandan adaha küçük ve daha büyüktür A.

strcasecmp()kabul edecektir Aolarak a*, ve o zamandan beri adaha büyük _çıkış da doğrudur.

* POSIX.1-2008 standardı bu işlevleri (strcasecmp () ve strncasecmp ()) söylüyor:

Kullanılan yerel ayarın LC_CTYPE kategorisi POSIX yerel ayarından olduğunda, bu işlevler, dizeler küçük harfe dönüştürülmüş gibi davranır ve ardından bir bayt karşılaştırması gerçekleştirilir. Aksi takdirde sonuçlar belirtilmez.

Kaynak: http://man7.org/linux/man-pages/man3/strcasecmp.3.html


3
OP'nin amacı, Abüyük / _küçük harfe duyarlı olmayan bir şekilde karşılaştırmaya kıyasla "daha büyük" olması ve sonucun büyük / küçük harfe duyarlı bir şekilde karşılaştırmayla neden aynı olmadığını merak ediyor.
anton.burger

6
Deyim Since a` olmanın geçersiz kesinti olduğu gibi A kabul edecek duyarsız strcasecmp () `durumdur. Büyük / küçük harfe duyarlı olmayan bir yordam, tüm büyük harflere küçük harfmiş gibi davranabilir, tüm küçük harflere büyük harfmiş gibi davranabilir veya her büyük harfe karşılık gelen küçük harfe ve tam tersi gibi davranabilir, ancak yine de bunları karşılaştırabilir Ham değerleri ile harf olmayan karakterlere. Bu cevap, bu olasılıklardan herhangi birini tercih etmek için bir neden belirtmez (bunun doğru nedeni, belgelerin küçük harf kullanmasıdır).
Eric Postpischil

@EricPostpischil POSIX.1-2008 standardı bu işlevleri (strcasecmp () ve strncasecmp ()) söylüyor: Kullanılan yerel ayarın LC_CTYPE kategorisi POSIX yerel ayarından geliyorsa, bu işlevler dizeler dönüştürülmüş gibi davranmalıdır. küçük harf ve sonra bir bayt karşılaştırma gerçekleştirildi. Aksi takdirde sonuçlar belirtilmez.
anastaciu
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.