【问题标题】:C++: case-insensitive first-n-characters string comparisonC++:不区分大小写的前 n 个字符的字符串比较
【发布时间】:2011-04-14 10:09:11
【问题描述】:

我的问题类似于this,但我有两个字符串(如char *),任务是将strnicmp 函数(仅适用于MS VC)替换为boost::iequals

注意 strnicmp 不是 stricmp - 它只比较前 n 个字符。

有没有比这更简单的解决方案:

void foo(const char *s1, const char *s2) 
{
    ...

    std::string str1 = s1;
    std::string str2 = s2;
    int n = 7;

    if (boost::iequals(str1.substr(0, n), str2)) {
        ...
    }
}

【问题讨论】:

  • 谢谢大家。我更喜欢Xeounwind 的答案。我从 c.l.c++ 知道 James Kanze 并尊重他作为专业人士,但在这种情况下,如果我有 char * 字符串,我更喜欢编写 C 样式函数而不是将它们转换为 std::string。但是James 的答案在std::strings 的情况下会很有趣,特别是如果您的编译器支持 lamda 表达式,因此您可以将EqIgnoreCase 替换为 lambda :) 全部获得 +1。
  • boost::iequals 适用于范围,您无需一直转换为 std::string
  • 无法弄清楚如何将boost::iequals 与范围一起使用。你能提供一个例子吗?
  • boost::iequals(boost:iterator_range(s1, s1+n), boost::iterator_range(s2, s2+n))。假设两个字符串至少和n一样长,否则先减少n

标签: c++ string boost stl


【解决方案1】:

如果真的有必要,写你自己的函数:

bool mystrnicmp(char const* s1, char const* s2, int n){
  for(int i=0; i < n; ++i){
    unsigned char c1 = static_cast<unsigned char>(s1[i]);
    unsigned char c2 = static_cast<unsigned char>(s2[i]);
    if(tolower(c1) != tolower(c2))
      return false;
    if(c1 == '\0' || c2 == '\0')
      break;
  }
  return true;
}

【讨论】:

  • 以及避免未定义行为所必需的static_cast&lt;unsigned char&gt;
  • 如果使用例如调用未定义的行为mystrnicmp("foo", "foo", 50).
  • @unwind:应该和现在一样安全,因为strlen 也依赖于空终止符。
  • 您实际上并不需要检查这两个字符是否为 0,因为您已经确定它们是不区分大小写的。不过,只检查一项可能会损害代码的清晰度。
【解决方案2】:

为了不区分大小写,您需要自定义比较函数 (或函子):

struct EqIgnoreCase
{
    bool operator()( char lhs, char rhs ) const
    {
        return ::tolower( static_cast<unsigned char>( lhs ) )
            == ::tolower( static_cast<unsigned char>( rhs ) );
    }
};

如果我理解正确,您正在检查前缀。这 最简单的方法是:

bool
isPrefix( std::string const& s1, std::string const& s2 )
{
    return s1.size() <= s2.size()
        && std::equals( s1.begin(), s1.end(), s2.begin(), EqIgnoreCase() );
}

(注意检查大小。s1不能是s2的前缀 if 它比s2 长。当然,std::equals 会 如果使用s1 调用的时间长于 s2.)

【讨论】:

  • 啊。废话,我的也是一样...我想我还是会离开的,因为我使用const char*作为std::equal的迭代器...
【解决方案3】:

对于一个根据 C 字符串(字符指针)定义的函数,“向上”到 STL 字符串的效率似乎非常低,但我认为这可能是完全不成熟的想法。

我会认为直接的 C 解决方案“更简单”,但这又取决于个人的观点。

#include <ctype.h>

void foo(const char *s1, const char *s2)
{
  size_t i, n = 7;

  for(i = 0; i < n; i++)
  {
    if(tolower(s1[i]) != tolower(s2[i]))
      return;
    if(s[i] == '\0' && s2[i] == '\0')
      break;
  }
  /* Strings are equal, do the work. */
  ...
}

这假设如果两个字符串在前缀长度用完之前结束,则匹配。

当然,上面假设tolower()有意义的ASCII字符串。

【讨论】:

  • 澄清一点:所有代码都是用 C++ 编写的,并且大量使用 STL 和 boost。这个函数使用strnicmp,因为我们从3dparty库中得到的数据结构包含char *字段
【解决方案4】:

我建议自己写函数,像这样:

bool strnicmp2(const char *s, const char *t, size_t n) {
    while (n > 0 && *s && *t && tolower(*s) == tolower(*t)) {
        ++s;
        ++t;
        --n;
    }
    return n == 0 || !*s || !*t;
}

【讨论】:

    【解决方案5】:

    这样的东西应该可以工作..

    #include <iostream>
    #include <string>
    #include <cctype>
    #include <cstring>
    #include <algorithm>
    
    struct isequal
    {
      bool operator()(int l, int r) const
      {
        return std::tolower(l) == std::tolower(r);
      }
    };
    
    bool istrncmp(const char* s1, const char* s2, size_t n)
    {
      size_t ls1 = std::strlen(s1);
      size_t ls2 = std::strlen(s2);
      // this is strict, but you can change
      if (ls1 < n || ls2 < n)
        return false;
    
      return std::equal(s1, s1 + n, s2, isequal()); 
    }
    
    int main(void)
    {
      std::cout << istrncmp("fooB", "fooA", 3) << std::endl;
      std::cout << istrncmp("fooB", "fooA", 5) << std::endl;
      std::cout << istrncmp("fooB", "f1oA", 3) << std::endl;
      return 0;
    }
    

    【讨论】:

      【解决方案6】:

      我不知道这算不算简单,但它的行数更少,速度应该不错。

      #include <boost/iterator/transform_iterator.hpp>
      #include <algorithm>
      #include <cctype>
      
      bool equal_insensitive_n( char const *a, char const *b, size_t n ) {
          n = std::min( n, std::min( ::strlen( a ) + 1, ::strlen( b ) + 1 ) );
          #define tilc(S) boost::make_transform_iterator( (S), ::tolower )
          return std::equals( tilc(a), tilc(a) + n, tilc(b) );
          #undef tilc
      }
      

      【讨论】:

        猜你喜欢
        • 2021-05-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-29
        • 2014-06-20
        相关资源
        最近更新 更多