【问题标题】:How do I change the sort order of underscores in STL?如何更改 STL 中下划线的排序顺序?
【发布时间】:2011-11-17 20:01:45
【问题描述】:

我有一个 C++ 应用程序,它使用 STL 集来保存字符串列表(有序且唯一)。

我遇到的问题是下划线的排列方式与我需要的相反。

示例 STL 订单:

"word0"
"word_"

我需要的顺序是:

"word_"
"word0"

我已经开始实现一个自定义比较函数来处理这个问题,但我宁愿使用 STL 中提供的解决方案(如果有的话)。

在网上搜索,我发现了一些对这个完全相同的问题的引用,但在其他系统中,解决方案似乎是更改排序规则或区域设置,但我似乎无法找到如何使用 STL .

【问题讨论】:

    标签: c++ sorting stl


    【解决方案1】:

    没有针对这个特定问题的内置解决方案,因为库希望您构建自己的自定义比较器来处理这个问题。

    但是,您可能需要考虑定义自己的 char_traits 类型,这样您就可以自定义字符串的排序和比较方式。虽然没有关于此的最佳在线教程,但这可能是解决您的问题的最干净和最简单的解决方案。作为一个无耻的插件,我给 this earlier question about char_traits 写了一个答案,这可能对你正在做的事情有用。

    我建议你不要乱用语言环境。语言环境是为本地化而设计的,旨在对文本的处理方式产生巨大而深远的影响。自定义比较器或新的char_traits 类型更直接地解决了手头的问题。

    【讨论】:

    • +1:我只想补充一点:如果您只需要在set(s) 中更改排序顺序 - 使用自定义比较器,这是最直接和预期的方式。如果您需要全局更改字符串的排序顺序(在您的应用程序范围内) - 使用您的自定义 char_traits 输入自定义字符串。
    【解决方案2】:

    Matt Austern 在"How to do case-insensitive string comparison" 上写了一篇正确处理语言环境的论文。它可能包含有关您正在寻找的语言环境和方面的信息。

    否则,如果您只是想颠倒几个字符的通常比较顺序,不应该将std::lexicographical_compare 与您自己的比较函数对象一起使用吗?

    bool mycomp( char c1, char c2 )
    {
        // Return 0x5F < 0x30
        if ( ( c1 == '_' ) && ( c2 == '0' ) )
            return true;
        if ( ( c1 == '0' ) && ( c2 == '_' ) )
            return false;
    
        return ( c1 < c2 );
    }
    
    std::string w1 = "word0";
    std::string w2 = "word_";
    
    bool t1 = std::lexicographical_compare( w1.begin(), w1.end(), w2.begin(), w2.end() );
    bool t2 = std::lexicographical_compare( w1.begin(), w1.end(), w2.begin(), w2.end(), mycomp );
    

    "word0" 在第一种情况下的计算结果小于"word_",而在第二种情况下则更大,这就是您所追求的。

    如果您已经在做类似的事情,这是最简单的方法。

    编辑:关于使用char_traits 完成此任务的主题,Austern 的文章指出:

    标准库类型std::string 使用traits 参数 所有比较,因此,通过提供具有相等性的特征参数和 小于适当地重新定义,您可以在 这样,&lt;== 运营商就可以满足您的需求。你 可以,但不值得这么麻烦。

    您将无法进行 I/O,至少不会没有很多痛苦。你 将无法使用像cincout 这样的普通流对象。

    他接着列出了其他几个很好的理由,说明为什么修改 char_traits 以执行此比较不是一个好主意。

    我强烈建议您阅读 Austern 的论文。

    【讨论】:

      【解决方案3】:

      您可以将std::lexicographic_compare 与自定义谓词一起使用,以将字符串与自定义字符顺序进行比较——正如 Gnawme 已经说过的那样。以下代码将std::setstd::lexicographic_compare 结合在一起。

      #include <iostream>
      #include <set>
      #include <string>
      #include <algorithm>
      
      struct comp
      {
          static bool compchar(char a, char b)
          {
              if (a == '0' && b == '_' || a == '_' && b == '0')
                  return !(a < b);
              else
                  return (a < b);
          }
      
          bool operator()(const std::string& a, const std::string& b) const
          {
              return std::lexicographical_compare(a.begin(), a.end(),
                                                  b.begin(), b.end(),
                                                  compchar);
          }
      };
      
      int main()
      {
          std::set<std::string, comp> test;
          test.insert("word0");
          test.insert("word_");
      
          for (std::set<std::string, comp>::const_iterator cit = test.begin();
               cit != test.end(); ++cit)
               std::cout << *cit << std::endl;
      
          return 0;
      }
      

      【讨论】:

        【解决方案4】:

        有一个 collate 类,这里有一个 C++ 中的 brief explanations of facet usage 以及一些如何使用它的示例。

        但你可能还是需要自己实现实际的逻辑。

        并且:“标准 C++ 库中的字符串类不提供任何区域敏感字符串比较服务。”因此,您还需要将语言环境使用包装在单独的比较函数中。

        因此,如果现有语言环境没有按照您喜欢的方式比较字符串,那么采用这种方式看起来有点矫枉过正。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-09-23
          • 2020-08-01
          • 2019-02-22
          • 2018-01-04
          • 1970-01-01
          • 2015-11-19
          • 1970-01-01
          相关资源
          最近更新 更多