[英]C++: case-insensitive first-n-characters string comparison
My question is similar to this , but I have two strings (as char *
) and the task is to replace strnicmp
function (avaible only for MS VC) with something like boost::iequals
. 我的问题与此类似,但我有两个字符串(作为
char *
),任务是用boost::iequals
替换strnicmp
函数(仅适用于MS VC)。
Note strnicmp
is not stricmp
- it only compares first n characters. 注意
strnicmp
不是stricmp
- 它只比较前n个字符。
Is there any solution simplier than this: 有没有比这更简单的解决方案:
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)) {
...
}
}
If it's really necessary, write your own function: 如果确实有必要,请编写自己的函数:
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;
}
For case insensitivity, you need a custom comparison function (or functor): 对于不区分大小写,您需要自定义比较函数(或仿函数):
struct EqIgnoreCase
{
bool operator()( char lhs, char rhs ) const
{
return ::tolower( static_cast<unsigned char>( lhs ) )
== ::tolower( static_cast<unsigned char>( rhs ) );
}
};
If I understand correctly, you're checking for a prefix. 如果我理解正确,您正在检查前缀。 The simplest way to do this is:
最简单的方法是:
bool
isPrefix( std::string const& s1, std::string const& s2 )
{
return s1.size() <= s2.size()
&& std::equals( s1.begin(), s1.end(), s2.begin(), EqIgnoreCase() );
}
(Note the check of the sizes. s1
can't be a prefix of s2
if it it longer than s2
. And of course, std::equals
will encounter undefined behavior if called with s1
longer than s2
.) (注意大小的检查。
s1
不可能的前缀s2
,如果它长于s2
。当然, std::equals
会遇到,如果调用未定义行为s1
长于s2
)。
For a function defined in terms of C strings (character pointers) going "up" to STL strings seems horribly inefficient, but maybe that's totally premature thinking on my part. 对于根据C字符串(字符指针)定义的函数,“向上”到STL字符串似乎非常低效,但也许这对我来说是完全过早的思考。
I would consider a straight C solution "simpler", but again that depends on one's perspective. 我认为直接的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. */
...
}
This assumes that if both strings end before the length of the prefix has been exhausted, it's a match. 这假设如果两个字符串在前缀长度用尽之前结束,那么它就是匹配。
Of course the above assumes ASCII strings where tolower()
makes sense. 当然,上面假设了
tolower()
有意义的ASCII字符串。
I suggest to write the function yourselfs, like this: 我建议自己写这个函数,像这样:
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;
}
something like this ought to work.. 像这样的东西应该工作..
#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;
}
I don't know if this counts as simpler or not, but it has fewer lines and speed should be pretty good. 我不知道这是否更简单,但它有更少的线条,速度应该是相当不错的。
#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
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.