क्या स्ट्रैसकेम्प एल्गोरिथ्म त्रुटिपूर्ण है?


34

मैं strcasecmpसी में फ़ंक्शन को फिर से लागू करने की कोशिश कर रहा हूं और मैंने देखा कि तुलनात्मक प्रक्रिया में एक असंगति प्रतीत होती है।

से man strcmp

Strcmp () फ़ंक्शन दो स्ट्रिंग्स s1 और s2 की तुलना करता है। लोकेल को ध्यान में नहीं रखा जाता है (स्थानीय-जागरूक तुलना के लिए, देखें स्ट्रैकोल (3))। यह s1 से कम, मिलान के लिए या s2 से अधिक होने के लिए क्रमशः एक पूर्णांक से कम, शून्य से अधिक या शून्य से अधिक रिटर्न देता है।

से man strcasecmp

Strcasecmp () फ़ंक्शन तार के s1 और s2 की बाइट-बाय-बाइट तुलना करता है, पात्रों के मामले की अनदेखी करता है। यह s1 से कम, मिलान के लिए या s2 से अधिक होने के लिए क्रमशः एक पूर्णांक से कम, शून्य से अधिक या शून्य से अधिक रिटर्न देता है।

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

यह जानकारी देते हुए, मुझे निम्नलिखित कोड के परिणाम की समझ नहीं है:

#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;
}

ouput:

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

ऐसा प्रतीत होता है कि, यदि वर्तमान वर्ण s1एक अक्षर है, तो इसे हमेशा निचले हिस्से में बदल दिया जाता है, भले ही वर्तमान वर्ण में s2कोई अक्षर हो या न हो।

क्या कोई इस व्यवहार की व्याख्या कर सकता है? क्या पहली और तीसरी पंक्ति एक जैसी नहीं होनी चाहिए?

आपका अग्रिम में ही बहुत धन्यवाद!

पुनश्च:
मैं gcc 9.2.0मंजरो पर उपयोग कर रहा हूं।
इसके अलावा, जब मैं -fno-builtinझंडे के साथ संकलित करता हूं तो मुझे इसके बजाय मिलता है:

-30
2
2
2

मुझे लगता है कि यह है क्योंकि कार्यक्रम gcc के अनुकूलित कार्यों का उपयोग नहीं करता है, लेकिन सवाल बना हुआ है।


2
अपने निर्धारित करने के लिए एक और परीक्षण का मामला जोड़ें: printf("%i\n", strcasecmp("a", "_"));यह शायद के रूप में एक ही परिणाम होना चाहिए printf("%i\n", strcasecmp("A", "_"));लेकिन इसका अर्थ यह है कि एक इन दो केस-संवेदी कॉल के अपने केस-संवेदी समकक्ष के साथ सहमत नहीं हो रहा है।
anton.burger

ऐसा लगता है कि strcasecmpआप जिस संदर्भ का उल्लेख कर रहे हैं, वह सटीक नहीं है। उत्कीर्ण उत्तरों में अधिक विवरण।
Jabberwocky

9
यह केवल एक चीज है जो समझ में आता है। एक फ़ंक्शन जो कहता है कि A < _ && a > _ && A == aबहुत सारी समस्याएं पैदा करेगा।
इकेगामी

एक तरफ: "मैं सी में strcasecmp फ़ंक्शन को फिर से लागू करने की कोशिश कर रहा हूं -> हालांकि कोड नहीं दिखाया गया है," जैसा है "की तुलना करना सुनिश्चित करें unsigned char। C17 / 18 "स्ट्रिंग हैंडलिंग <string.h>" -> "इस उपखंड में सभी कार्यों के लिए, प्रत्येक वर्ण की व्याख्या की जाएगी जैसे कि उसका प्रकार था unsigned char"। एक बार charASCII रेंज 0-127 के बाहर मानों पर फर्क पड़ता है।
chux -

1
बिल्ट-इन और इसके साथ आउटपुट में अंतर पर: दोनों एक ही कहते हैं, क्योंकि उनके परिणाम समान रूप से <0 और> 0 हैं, और आपके पास == 0 के लिए कोई उदाहरण नहीं है। लेकिन आप एल्गोरिदम को चमकते हुए देख सकते हैं: कुछ लौटाए गए मूल्य पहले गैर-बराबर चरित्र के अंतर हैं।
व्यस्त

जवाबों:


31

व्यवहार सही है।

POSIX str\[n\]casecmp()विनिर्देश प्रति :

जब LC_CTYPEइस्तेमाल की जा रही लोकेल की श्रेणी पोसिक्स लोकेल से होती है, तो ये कार्य इस तरह से व्यवहार करेंगे जैसे कि तार को लोअरकेस में बदल दिया गया था और फिर एक बाइट तुलना की गई थी। अन्यथा, परिणाम अनिर्दिष्ट हैं।

यह भी लिनक्स आदमी पृष्ठ के नोट अनुभाग का हिस्सा है :

POSIX.1-2008 मानक इन कार्यों के बारे में कहता है:

जब इस्तेमाल किए जा रहे लोकल की LC_CTYPE श्रेणी POSIX लोकेल से होती है, तो ये फ़ंक्शन ऐसा व्यवहार करेंगे जैसे कि तार को लोअरकेस में बदल दिया गया था और फिर एक बाइट तुलना की गई थी। अन्यथा, परिणाम अनिर्दिष्ट हैं।

क्यों?

जैसा कि @HansOlsson ने अपने उत्तर में बताया , केवल पत्रों के बीच केस-असंवेदनशील तुलना करना और अन्य सभी तुलनाओं को उनके "प्राकृतिक" परिणाम प्राप्त करने की अनुमति देना , जैसे strcmp()छँटाई करना।

यदि 'A' == 'a'(केस-असंवेदनशील तुलना की परिभाषा) तो '_' > 'A'और '_' < 'a'(ASCII वर्ण सेट में "प्राकृतिक" परिणाम) दोनों सत्य नहीं हो सकते।


केवल पत्रों के बीच केस-असंवेदनशील तुलना करने से परिणाम नहीं होगा '_' > 'A' && '_' < 'a'; सबसे अच्छा उदाहरण नहीं लगता है।
विंग्स

1
@AsteroidsWithWings वे प्रश्न में प्रयुक्त अक्षर हैं। और अगर 'a' == 'A' परिभाषा से , यदि आप "प्राकृतिक" मूल्यों के बीच तुलना करना 'a', 'A'और '_', आप नहीं कर सकते हैं जो केस-संवेदी तुलना करना 'A'और 'a'समानता हो और सुसंगत तरह परिणाम प्राप्त करने के।
एंड्रयू हेनले

मैं वह विवादित नहीं हूं, लेकिन आपके द्वारा प्रदान किया गया विशिष्ट काउंटर-उदाहरण प्रासंगिक नहीं लगता है।
पंखों के साथ क्षुद्रग्रह

से एक द्विआधारी पेड़ के निर्माण के मानसिक व्यायाम के माध्यम से @AsteroidsWithWings जाओ 'a', 'A'और '_'प्रस्तावित "केवल अक्षर परिवर्तित, पेड़ में प्रविष्टि के सभी 6 आदेश के माध्यम से जा रहा है, और प्रश्न के लिए के रूप में निर्दिष्ट" हमेशा छोटे अक्षरों "से परिणाम की तुलना जब यह पत्र-दर-अक्षर तुलना हो ”। उदाहरण के लिए, बाद के एल्गोरिथ्म का उपयोग करना और उसके साथ शुरू करना '_', 'a'और 'A'पेड़ के विपरीत पक्षों पर हवा करना , फिर भी उन्हें समान रूप से परिभाषित किया गया है। "केवल अक्षरों को पत्र-पत्र की तुलना में निचले मामले में परिवर्तित करें" एल्गोरिथ्म टूट गया है और उन 3 वर्णों से पता चलता है कि।
एंड्रयू हेनले

ठीक है, तो मैं सुझाव देता हूं कि उत्तर में यह दिखाओ क्योंकि इस समय यह इंगित करने के लिए कूदता है कि " '_' > 'A' और '_' < 'a'दोनों सच नहीं हो सकते" हमें बताए बिना कि हमें कभी यह क्यों सोचना चाहिए था। (यह जवाब देने वाले के लिए एक काम है, लाखों पाठकों में से एक के लिए नहीं।)
क्षुद्रग्रहों के साथ पंख

21

अन्य लिंक, http://man7.org/linux/man-pages/man3/strcasecmp.3p.html के लिए strcasecmp का कहना है कि निचले-मामले में परिवर्तित करना सही व्यवहार है (कम से कम POSIX लोकेल में)।

उस व्यवहार का कारण यह है कि यदि आप strcasecmp का उपयोग स्ट्रिंग्स की एक सरणी को सॉर्ट करने के लिए करते हैं तो उचित परिणाम प्राप्त करने के लिए इसकी आवश्यकता होती है।

अन्यथा यदि आप "ए", "सी", "_", "बी" को छाँटने की कोशिश करते हैं, उदाहरण के लिए, तो qsort परिणाम तुलना के क्रम पर निर्भर करेगा।


3
अन्यथा यदि आप "ए", "सी", "_", "बी" को छाँटने की कोशिश करते हैं, उदाहरण के लिए, तो qsort परिणाम तुलना के क्रम पर निर्भर करेगा। अच्छी बात। यही कारण है कि कारण POSIX व्यवहार को निर्दिष्ट करता है।
एंड्रयू हेनले

6
अधिक संक्षेप में, आपको छँटाई के लिए कुल आदेश की आवश्यकता होती है , जो कि यदि आप तुलना को प्रश्न के रूप में परिभाषित करते हैं तो मामला नहीं होगा (क्योंकि यह सकर्मक नहीं होगा)।
Dukeling

8

ऐसा प्रतीत होता है कि, यदि s1 में वर्तमान वर्ण एक अक्षर है, तो इसे हमेशा लोअरकेस में बदल दिया जाता है, भले ही s2 में वर्तमान वर्ण एक अक्षर है या नहीं।

यह सही है - और यह है कि strcasecmp()फ़ंक्शन क्या करना चाहिए ! यह मानक के POSIXभाग के बजाय एक फ़ंक्शन है, Cलेकिन " द ओपन ग्रुप बेस स्पेसिफिकेशन्स, अंक 6 " से।

POSIX लोकेल में, strcasecmp () और strncasecmp () इस तरह व्यवहार करेंगे जैसे कि तार को लोअरकेस में बदल दिया गया था और फिर एक बाइट तुलना की गई। परिणाम अन्य स्थानों पर अनिर्दिष्ट हैं।

संयोग से, यह व्यवहार _stricmp()फ़ंक्शन के अनुसार भी है (जैसा कि Visual Studio / MSCV में उपयोग किया जाता है):

_Stricmp फ़ंक्शन आमतौर पर प्रत्येक वर्ण को लोअरकेस में परिवर्तित करने के बाद string1 और string2 की तुलना करता है, और उनके रिश्ते को दर्शाता एक मान लौटाता है।


2

के लिए ASCII दशमलव कोड Aहै 65के लिए _है 95और के लिए aहै 97, इसलिए strcmp()यह कर रहा है क्या यह करने के लिए मान लीजिए है। लेक्सोग्राफिक रूप से बोलना _छोटा aऔर फिर से बड़ा है A

strcasecmp()* के Aरूप में संबंध होगा a, और चूंकि उत्पादन aसे बड़ा _है भी सही है।

* POSIX.1-2008 मानक इन कार्यों (strcasecmp () और strncasecmp ()) के बारे में कहता है:

जब इस्तेमाल किए जा रहे लोकल की LC_CTYPE श्रेणी POSIX लोकेल से होती है, तो ये फ़ंक्शन ऐसा व्यवहार करेंगे जैसे कि तार को लोअरकेस में बदल दिया गया था और फिर एक बाइट तुलना की गई थी। अन्यथा, परिणाम अनिर्दिष्ट हैं।

स्रोत: http://man7.org/linux/man-pages/man3/strcasecmp.3.html


3
ओपी का कहना है कि केस-असंवेदनशील की तुलना Aमें "बड़ा" है _, और आश्चर्य होता है कि केस-सेंसिटिवली तुलना करने पर परिणाम समान नहीं होता है।
एंटोन.बर्गर

6
स्टेटमेंट Since strcasecmp () `केस असंवेदनशील है क्योंकि यह ए को 'ए' माना जाएगा क्योंकि यह एक अवैध कटौती है। केस-असंवेदनशील दिनचर्या सभी अपरकेस अक्षरों का इलाज कर सकती है जैसे कि वे लोअरकेस अक्षर थे, सभी लोअरकेस अक्षरों का इलाज कर सकते थे जैसे कि वे अपरकेस अक्षर थे, या प्रत्येक अपरकेस लेटर को उसके संबंधित लोअरकेस लेटर और इसके विपरीत के बराबर मान सकते हैं लेकिन फिर भी उनकी तुलना करें अपने कच्चे मूल्यों के साथ गैर-अक्षर वाले अक्षर। यह उत्तर उन संभावनाओं में से किसी को प्राथमिकता देने का एक कारण नहीं बताता है (जिसके लिए सही कारण यह है कि प्रलेखन लोअरकेस का उपयोग करने के लिए कहता है)।
एरिक पोस्टपिसिल

@EricPostpischil POSIX.1-2008 मानक इन फ़ंक्शंस (strcasecmp () और strncasecmp ()) के बारे में कहता है: जब उपयोग किए जा रहे लोकल की LC_CTYPE श्रेणी POSIX लोकेल से होती है, तो ये फ़ंक्शन ऐसा व्यवहार करेंगे जैसे कि स्ट्रिंग्स को परिवर्तित कर दिया गया हो। लोअरकेस और फिर एक बाइट तुलना का प्रदर्शन किया। अन्यथा, परिणाम अनिर्दिष्ट हैं।
anastaciu
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.