2012-12-13 11 views
12

मैं वर्णमाला के क्रम में फ़ाइलों को सॉर्ट करने के लिए निम्नलिखित कोड का इस्तेमाल किया है और यह के रूप में चित्र में दिखाया गया फ़ाइलें सॉर्ट करता:सी में क्रम में संख्याओं और अक्षरों के साथ फ़ाइल नामों को सॉर्ट करने के लिए कैसे करें?

for(int i = 0;i < maxcnt;i++) 
{ 
    for(int j = i+1;j < maxcnt;j++) 
    {   
     if(strcmp(Array[i],Array[j]) > 0) 
     {    
      strcpy(temp,Array[i]);  
      strcpy(Array[i],Array[j]);  
      strcpy(Array[j],temp);  
     }  
    } 
} 

enter image description here

लेकिन मैं के रूप में आदेश विंडोज एक्सप्लोरर

में देखा यह सॉर्ट करने के लिए की जरूरत है

enter image description here

इस तरह से कैसे क्रमबद्ध करें? कृपया

+0

जब आप तुलना करते हैं, तो पहले तारों से संख्याओं को निकालें, फिर संख्याओं की तुलना करें। – wimh

+1

@ विममेल: यह एक ही उपसर्ग वाले सभी फ़ाइल नामों पर निर्भर करता है, जो मुझे लगता है कि यह आवश्यक नहीं है। यह सभी फ़ाइल नामों पर भी निर्भर करता है जिनमें बिल्कुल एक (शून्य नहीं, दो नहीं) संख्यात्मक घटक होता है। – NPE

+3

असंबद्ध: स्वैपिंग के लिए तारों की प्रतिलिपि क्यों करें? बस पॉइंटर्स को स्वैप करें (और वहां 'std :: swap' ... है)। –

उत्तर

6

C उत्तर के लिए, निम्नलिखित strcasecmp() के लिए एक प्रतिस्थापन है। यह फ़ंक्शन उन तारों को संभालने के लिए पुनरावर्ती है जिनमें वैकल्पिक संख्यात्मक और गैर-संख्यात्मक सबस्ट्रिंग शामिल हैं।आप qsort() के साथ उपयोग कर सकते हैं:

int strcasecmp_withNumbers(const void *void_a, const void *void_b) { 
    const char *a = void_a; 
    const char *b = void_b; 

    if (!a || !b) { // if one doesn't exist, other wins by default 
     return a ? 1 : b ? -1 : 0; 
    } 
    if (isdigit(*a) && isdigit(*b)) { // if both start with numbers 
     char *remainderA; 
     char *remainderB; 
     long valA = strtol(a, &remainderA, 10); 
     long valB = strtol(b, &remainderB, 10); 
     if (valA != valB) 
     return valA - valB; 
     // if you wish 7 == 007, comment out the next two lines 
     else if (remainderB - b != remainderA - a) // equal with diff lengths 
     return (remainderB - b) - (remainderA - a); // set 007 before 7 
     else // if numerical parts equal, recurse 
     return strcasecmp_withNumbers(remainderA, remainderB); 
    } 
    if (isdigit(*a) || isdigit(*b)) { // if just one is a number 
     return isdigit(*a) ? -1 : 1; // numbers always come first 
    } 
    while (*a && *b) { // non-numeric characters 
     if (isdigit(*a) || isdigit(*b)) 
     return strcasecmp_withNumbers(a, b); // recurse 
     if (tolower(*a) != tolower(*b)) 
     return tolower(*a) - tolower(*b); 
     a++; 
     b++; 
    } 
    return *a ? 1 : *b ? -1 : 0; 
} 

नोट्स:

  • विंडोज यूनिक्स से stricmp() की जरूरत है बल्कि बराबर strcasecmp()
  • उपरोक्त कोड (स्पष्ट रूप से) गलत परिणाम देगा यदि संख्या वास्तव में बड़ी है।
  • अग्रणी शून्य यहां अनदेखा कर रहे हैं। मेरे क्षेत्र में, यह एक विशेषता है, बग नहीं: हम आमतौर पर UALसे UAL123 से मेल खाते हैं। लेकिन यह आपके लिए आवश्यक हो सकता है या नहीं भी हो सकता है।
  • Sort on a string that may contain a number और How to implement a natural sort algorithm in c++? भी देखें, हालांकि वहां के उत्तर, या उनके लिंक में, उपरोक्त कोड की तुलना में कम से कम चार कारकों की तुलना में निश्चित रूप से लंबी और रैंपिंग हैं।
+0

धन्यवाद यूसुफ बहुत बहुत धन्यवाद !! – indira

5

जो आप करना चाहते हैं वह "प्राकृतिक सॉर्ट" करने में मदद करें। इसके बारे में Here is a blog post, मुझे विश्वास है कि अजगर में कार्यान्वयन की व्याख्या है। Here एक पर्ल मॉड्यूल है जो इसे पूरा करता है। How to implement a natural sort algorithm in c++?

5

प्राकृतिक सॉर्टिंग एक ऐसा प्रश्न भी है जो आपको यहां लेना चाहिए। मेरे परिदृश्य के लिए मेरे पास एक कामकाजी कोड है। आप शायद इसे अपनी आवश्यकताओं के अनुसार बदलकर इसका उपयोग कर सकते हैं:

#ifndef JSW_NATURAL_COMPARE 
    #define JSW_NATURAL_COMPARE 
    #include <string> 
    int natural_compare(const char *a, const char *b); 
    int natural_compare(const std::string& a, const std::string& b); 
    #endif 
    #include <cctype> 
    namespace { 
     // Note: This is a convenience for the natural_compare 
     // function, it is *not* designed for general use 
     class int_span { 
     int _ws; 
     int _zeros; 
     const char *_value; 
     const char *_end; 
     public: 
     int_span(const char *src) 
     { 
      const char *start = src; 
      // Save and skip leading whitespace 
      while (std::isspace(*(unsigned char*)src)) ++src; 
      _ws = src - start; 
      // Save and skip leading zeros 
      start = src; 
      while (*src == '0') ++src; 
      _zeros = src - start; 
      // Save the edges of the value 
      _value = src; 
      while (std::isdigit(*(unsigned char*)src)) ++src; 
      _end = src; 
     } 
     bool is_int() const { return _value != _end; } 
     const char *value() const { return _value; } 
     int whitespace() const { return _ws; } 
     int zeros() const { return _zeros; } 
     int digits() const { return _end - _value; } 
     int non_value() const { return whitespace() + zeros(); } 
     }; 
     inline int safe_compare(int a, int b) 
     { 
     return a < b ? -1 : a > b; 
     } 
    } 
    int natural_compare(const char *a, const char *b) 
    { 
     int cmp = 0; 
     while (cmp == 0 && *a != '\0' && *b != '\0') { 
     int_span lhs(a), rhs(b); 
     if (lhs.is_int() && rhs.is_int()) { 
      if (lhs.digits() != rhs.digits()) { 
      // For differing widths (excluding leading characters), 
      // the value with fewer digits takes priority 
      cmp = safe_compare(lhs.digits(), rhs.digits()); 
      } 
      else { 
      int digits = lhs.digits(); 
      a = lhs.value(); 
      b = rhs.value(); 
      // For matching widths (excluding leading characters), 
      // search from MSD to LSD for the larger value 
      while (--digits >= 0 && cmp == 0) 
       cmp = safe_compare(*a++, *b++); 
      } 
      if (cmp == 0) { 
      // If the values are equal, we need a tie 
      // breaker using leading whitespace and zeros 
      if (lhs.non_value() != rhs.non_value()) { 
       // For differing widths of combined whitespace and 
       // leading zeros, the smaller width takes priority 
       cmp = safe_compare(lhs.non_value(), rhs.non_value()); 
      } 
      else { 
       // For matching widths of combined whitespace 
       // and leading zeros, more whitespace takes priority 
       cmp = safe_compare(rhs.whitespace(), lhs.whitespace()); 
      } 
      } 
     } 
     else { 
      // No special logic unless both spans are integers 
      cmp = safe_compare(*a++, *b++); 
     } 
     } 
     // All else being equal so far, the shorter string takes priority 
     return cmp == 0 ? safe_compare(*a, *b) : cmp; 
    } 
    #include <string> 
    int natural_compare(const std::string& a, const std::string& b) 
    { 
     return natural_compare(a.c_str(), b.c_str()); 
    } 
0

आपकी समस्या यह है कि आपके पास फ़ाइल नाम के कुछ हिस्सों के पीछे एक व्याख्या है।

लेक्सिकोोग्राफ़िकल क्रम में, Slide1Slide10 से पहले Slide5 से पहले है।

आप Slide5Slide10 से पहले उम्मीद के रूप में आप सबस्ट्रिंग 5 और 10 (पूर्णांक के रूप में) की एक व्याख्या की है।

यदि आपके पास फ़ाइल नाम में महीने का नाम था, तो आप अधिक समस्याओं में भाग लेंगे, और उम्मीद है कि उन्हें तिथि के अनुसार आदेश दिया जाएगा (यानी जनवरी अगस्त से पहले आता है)। आपको इस व्याख्यान में अपनी सॉर्टिंग को समायोजित करने की आवश्यकता होगी (और "प्राकृतिक" आदेश आपकी व्याख्या पर निर्भर करेगा, कोई सामान्य समाधान नहीं है)।

एक अन्य तरीका फ़ाइल नामों को इस तरह प्रारूपित करना है कि आपका सॉर्टिंग और लेक्सिकोोग्राफ़िक ऑर्डर सहमत हो। आपके मामले में, आप अग्रणी शून्य और संख्या के लिए एक निश्चित लंबाई का उपयोग करेंगे। तो Slide1Slide01 बन जाता है, और फिर आप देखेंगे कि उन्हें क्रमबद्ध रूप से क्रमबद्ध रूप से परिणाम मिलेगा जो आप चाहते हैं।

हालांकि, अक्सर आप किसी एप्लिकेशन के आउटपुट को प्रभावित नहीं कर सकते हैं, और इस प्रकार सीधे आपके प्रारूप को लागू नहीं कर सकते हैं।

मैं उन मामलों में क्या करता हूं: फ़ाइल को एक उचित प्रारूप में नामित करने वाली छोटी स्क्रिप्ट/फ़ंक्शन लिखें, और फिर उन्हें क्रमबद्ध करने के लिए मानक सॉर्टिंग एल्गोरिदम का उपयोग करें। इसका लाभ यह है कि आपको अपनी सॉर्टिंग को अनुकूलित करने की आवश्यकता नहीं है, और सॉर्टिंग के लिए मौजूदा सॉफ़्टवेयर का उपयोग कर सकते हैं। नकारात्मक पक्ष में, ऐसी स्थितियां हैं जहां यह व्यवहार्य नहीं है (क्योंकि फ़ाइल नामों को ठीक करने की आवश्यकता है)।

+0

मेरे मामले में, फ़ाइल नाम तय किए गए हैं। – indira

5

ध्यान में रखते हुए कि यह एक c++ टैग है, तो आप @Joseph Quinsey के जवाब पर विस्तृत और एक natural_less समारोह मानक पुस्तकालय को पास करने की बना सकते हैं।

using namespace std; 

bool natural_less(const string& lhs, const string& rhs) 
{ 
    return strcasecmp_withNumbers(lhs.c_str(), rhs.c_str()) < 0; 
} 

void example(vector<string>& data) 
{ 
    std::sort(data.begin(), data.end(), natural_less); 
} 

मैं समय लगा एक व्यायाम https://github.com/kennethlaskoski/natural_less

2

this जवाब में संशोधन के रूप में कुछ काम कर कोड लिखने के लिए:

bool compareNat(const std::string& a, const std::string& b){ 
    if (a.empty()) 
     return true; 
    if (b.empty()) 
     return false; 
    if (std::isdigit(a[0]) && !std::isdigit(b[0])) 
     return true; 
    if (!std::isdigit(a[0]) && std::isdigit(b[0])) 
     return false; 
    if (!std::isdigit(a[0]) && !std::isdigit(b[0])) 
    { 
     if (a[0] == b[0]) 
      return compareNat(a.substr(1), b.substr(1)); 
     return (toUpper(a) < toUpper(b)); 
     //toUpper() is a function to convert a std::string to uppercase. 
    } 

    // Both strings begin with digit --> parse both numbers 
    std::istringstream issa(a); 
    std::istringstream issb(b); 
    int ia, ib; 
    issa >> ia; 
    issb >> ib; 
    if (ia != ib) 
     return ia < ib; 

    // Numbers are the same --> remove numbers and recurse 
    std::string anew, bnew; 
    std::getline(issa, anew); 
    std::getline(issb, bnew); 
    return (compareNat(anew, bnew)); 
} 

toUpper() समारोह:

std::string toUpper(std::string s){ 
    for(int i=0;i<(int)s.length();i++){s[i]=toupper(s[i]);} 
    return s; 
    } 

उपयोग:

#include <iostream> // std::cout 
#include <string> 
#include <algorithm> // std::sort, std::copy 
#include <iterator> // std::ostream_iterator 
#include <sstream> // std::istringstream 
#include <vector> 
#include <cctype> // std::isdigit 

int main() 
{ 
    std::vector<std::string> str; 
    str.push_back("20.txt"); 
    str.push_back("10.txt"); 
    str.push_back("1.txt"); 
    str.push_back("z2.txt"); 
    str.push_back("z10.txt"); 
    str.push_back("z100.txt"); 
    str.push_back("1_t.txt"); 
    str.push_back("abc.txt"); 
    str.push_back("Abc.txt"); 
    str.push_back("bcd.txt"); 

    std::sort(str.begin(), str.end(), compareNat); 
    std::copy(str.begin(), str.end(), 
       std::ostream_iterator<std::string>(std::cout, "\n")); 
} 
+0

यह नहीं बहुत ही कुशल, एक अधिक कुशल और व्यापक समाधान है है [यह एक] (http://stackoverflow.com/a/33880554/3744681) – Jahid

+0

ऊपर समाधान काम करता है, लेकिन अभी भी में समान नाम वाली बेशुमार फ़ाइलों देता है तल। यह वांछित परिणाम नहीं है। – Gaugeforever

संबंधित मुद्दे

 संबंधित मुद्दे