13

次のコードを使用してファイルをアルファベット順に並べ替え、図に示すようにファイルを並べ替えます。

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

ここに画像の説明を入力してください

しかし、Windowsエクスプローラーで見られる順序で並べ替える必要があります

ここに画像の説明を入力してください

このように並べ替える方法は?助けてください

4

6 に答える 6

7

答えとして、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;
}

ノート:

  • Windowsはstricmp()、Unixに相当するものではなく必要strcasecmp()です。
  • 上記のコードは、数値が本当に大きい場合、(明らかに)誤った結果をもたらします。
  • ここでは、先行ゼロは無視されます。私の地域では、これはバグではなく機能です。通常、UAL0123をUAL123と一致させたいと考えています。しかし、これはあなたが必要とするものかもしれないし、そうでないかもしれません。
  • 数値を含む可能性のある文字列での並べ替えおよびc++で自然並べ替えアルゴリズムを実装する方法も参照してください。、そこまたはそれらのリンクの答えは確かに長く、上記のコードと比較して、少なくとも4倍はとりとめのないものです。
于 2012-12-13T11:54:34.450 に答える
6

自然順はあなたがここで取らなければならない方法です。シナリオに使用できるコードがあります。あなたはおそらくあなたのニーズに応じてそれを変更することによってそれを利用することができます:

    #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());
    }
于 2012-12-13T09:55:04.440 に答える
5

あなたがしたいのは「自然順」を実行することです。これはそれについてのブログ投稿で、私が信じているPythonでの実装について説明しています。これを実現するperlモジュールは次のとおりですC++で自然ソートアルゴリズムを実装する方法にも同様の質問があるようです。

于 2012-12-13T09:46:49.487 に答える
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

于 2012-12-15T21:24:13.270 に答える
3

この回答の変更:

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"));
}
于 2015-11-03T09:42:29.263 に答える
0

あなたの問題は、ファイル名の一部の背後に解釈があることです。

辞書式順序でSlide1は、前Slide10は前Slide5です。

部分文字列と(整数として)の解釈があるので、Slide5前に期待します。Slide10510

ファイル名に月の名前が含まれていて、日付順に並べられると予想される場合(つまり、1月が8月より前になる場合)、さらに多くの問題が発生します。この解釈に合わせて並べ替えを調整する必要があります(「自然な」順序は解釈に依存します。一般的な解決策はありません)。

別のアプローチは、ソートと辞書式順序が一致するようにファイル名をフォーマットすることです。あなたの場合、あなたは先行ゼロと数の固定長を使用するでしょう。したがって、にSlide1なりSlide01、辞書式順序で並べ替えると、希望する結果が得られることがわかります。

ただし、多くの場合、アプリケーションの出力に影響を与えることができないため、フォーマットを直接適用することはできません。

そのような場合に私が行うこと:ファイルの名前を適切な形式に変更する小さなスクリプト/関数を作成し、標準の並べ替えアルゴリズムを使用してそれらを並べ替えます。これの利点は、ソートを調整する必要がなく、ソートに既存のソフトウェアを使用できることです。欠点としては、これが実行できない状況があります(ファイル名を修正する必要があるため)。

于 2012-12-13T10:07:56.850 に答える