Rob*_*Rob 310
Boost包含一个方便的算法:
#include <boost/algorithm/string.hpp>
// Or, for fewer header dependencies:
//#include <boost/algorithm/string/predicate.hpp>
std::string str1 = "hello, world!";
std::string str2 = "HELLO, WORLD!";
if (boost::iequals(str1, str2))
{
// Strings are identical
}
Run Code Online (Sandbox Code Playgroud)
wil*_*ell 116
利用标准char_traits.回想一下,a std::string实际上是一个typedef std::basic_string<char>,或更明确地说std::basic_string<char, std::char_traits<char> >.该char_traits类型描述了字符如何比较,如何复制,如何转换等等.您需要做的就是键入一个新的字符串basic_string,并为它提供自己的自定义char_traits,比较不区分大小写.
struct ci_char_traits : public char_traits<char> {
static bool eq(char c1, char c2) { return toupper(c1) == toupper(c2); }
static bool ne(char c1, char c2) { return toupper(c1) != toupper(c2); }
static bool lt(char c1, char c2) { return toupper(c1) < toupper(c2); }
static int compare(const char* s1, const char* s2, size_t n) {
while( n-- != 0 ) {
if( toupper(*s1) < toupper(*s2) ) return -1;
if( toupper(*s1) > toupper(*s2) ) return 1;
++s1; ++s2;
}
return 0;
}
static const char* find(const char* s, int n, char a) {
while( n-- > 0 && toupper(*s) != toupper(a) ) {
++s;
}
return s;
}
};
typedef std::basic_string<char, ci_char_traits> ci_string;
Run Code Online (Sandbox Code Playgroud)
细节是关于第29周的大师.
Tim*_*mmm 75
增强的问题在于你必须链接并依赖于提升.在某些情况下并不容易(例如android).
并且使用char_traits意味着所有比较都不区分大小写,这通常不是您想要的.
这应该足够了.它应该是合理有效的.虽然不处理unicode或其他任何东西.
bool iequals(const string& a, const string& b)
{
unsigned int sz = a.size();
if (b.size() != sz)
return false;
for (unsigned int i = 0; i < sz; ++i)
if (tolower(a[i]) != tolower(b[i]))
return false;
return true;
}
Run Code Online (Sandbox Code Playgroud)
更新:Bonus C++ 14 version(#include <algorithm>):
bool iequals(const string& a, const string& b)
{
return std::equal(a.begin(), a.end(),
b.begin(), b.end(),
[](char a, char b) {
return tolower(a) == tolower(b);
});
}
Run Code Online (Sandbox Code Playgroud)
Der*_*ark 55
如果您使用的是POSIX系统,则可以使用strcasecmp.但是,此功能不是标准C的一部分,也不适用于Windows.这将对8位字符执行不区分大小写的比较,只要语言环境是POSIX即可.如果语言环境不是POSIX,则结果是未定义的(因此它可能会进行本地化比较,也可能不会).没有宽字符的等价物.
如果做不到这一点,大量历史C库实现都具有stricmp()和strnicmp()函数.Windows上的Visual C++通过在前面添加下划线来重命名所有这些,因为它们不是ANSI标准的一部分,因此在该系统上它们被称为_stricmp或_strnicmp.某些库也可能具有宽字符或多字节等效函数(通常命名为例如wcsicmp,mbcsicmp等).
C和C++都基本上不了解国际化问题,因此除了使用第三方库之外,没有好的解决方案.如果您需要一个强大的C/C++库,请查看IBM ICU(Unicode的国际组件).ICU适用于Windows和Unix系统.
Coi*_*oin 52
你在谈论一个愚蠢的不区分大小写的比较或完全标准化的Unicode比较吗?
愚蠢的比较不会找到可能相同但不是二进制相等的字符串.
例:
U212B (ANGSTROM SIGN)
U0041 (LATIN CAPITAL LETTER A) + U030A (COMBINING RING ABOVE)
U00C5 (LATIN CAPITAL LETTER A WITH RING ABOVE).
Run Code Online (Sandbox Code Playgroud)
都是等价的,但它们也有不同的二进制表示.
也就是说,Unicode规范化应该是强制性的读取,特别是如果您计划支持Hangul,Thaï和其他亚洲语言.
此外,IBM还获得了大多数优化的Unicode算法专利,并将其公之于众.他们还维护一个实现:IBM ICU
Igo*_*kov 31
在字符串的情况下,boost :: iequals不兼容utf-8.您可以使用boost :: locale.
comparator<char,collator_base::secondary> cmpr;
cout << (cmpr(str1, str2) ? "str1 < str2" : "str1 >= str2") << endl;
Run Code Online (Sandbox Code Playgroud)
Sha*_*531 29
我对非unicode版本的第一个想法是做这样的事情:
bool caseInsensitiveStringCompare(const string& str1, const string& str2) {
if (str1.size() != str2.size()) {
return false;
}
for (string::const_iterator c1 = str1.begin(), c2 = str2.begin(); c1 != str1.end(); ++c1, ++c2) {
if (tolower(*c1) != tolower(*c2)) {
return false;
}
}
return true;
}
Run Code Online (Sandbox Code Playgroud)
bra*_*ray 18
您可以strcasecmp在Unix或stricmpWindows上使用.
到目前为止还没有提到的一件事是,如果你使用这些方法的stl字符串,首先比较两个字符串的长度是有用的,因为这个信息已经在字符串类中可用了.如果您比较的两个字符串首先不是相同的长度,这可能会阻止进行昂贵的字符串比较.
Dar*_*opp 14
支持unicode的Visual C++字符串函数:http://msdn.microsoft.com/en-us/library/cc194799.aspx
你可能正在寻找的是 _wcsnicmp
Ada*_*dam 13
我正在努力拼凑所有帖子的好答案,所以帮我编辑一下:
这是一个这样做的方法,虽然它确实转换了字符串,并且不是Unicode友好的,它应该是可移植的,这是一个加号:
bool caseInsensitiveStringCompare( const std::string& str1, const std::string& str2 ) {
std::string str1Cpy( str1 );
std::string str2Cpy( str2 );
std::transform( str1Cpy.begin(), str1Cpy.end(), str1Cpy.begin(), ::tolower );
std::transform( str2Cpy.begin(), str2Cpy.end(), str2Cpy.begin(), ::tolower );
return ( str1Cpy == str2Cpy );
}
Run Code Online (Sandbox Code Playgroud)
从我所看到的,这比stricmp()更便携,因为stricmp()实际上不是std库的一部分,但只是由大多数编译器供应商实现.
为了获得真正的Unicode友好实现,你必须走出std库.一个好的第三方库是IBM ICU(Unicode的国际组件)
另外boost :: iequals为进行这种比较提供了相当好的实用工具.
Wed*_*dge 11
仅供参考,strcmp()并且stricmp()容易受到缓冲区溢出的影响,因为它们只是处理直到它们达到空终止符.使用_strncmp()和更安全_strnicmp().
Dea*_*ing 11
该Boost.String图书馆有很多算法做案例insenstive比较等.
你可以实现自己的,但为什么它已经完成了呢?
vin*_*'th 11
str1.size() == str2.size() && std::equal(str1.begin(), str1.end(), str2.begin(), [](auto a, auto b){return std::tolower(a)==std::tolower(b);})
Run Code Online (Sandbox Code Playgroud)
如果你不能使用boost,你可以在C++ 14中使用上面的代码.你必须使用std::towlower宽字符.
对于我的基本不区分大小写的字符串比较需求,我不想使用外部库,也不希望单独的字符串类具有与我的所有其他字符串不兼容的不区分大小写的特征.
所以我想出的是:
bool icasecmp(const string& l, const string& r)
{
return l.size() == r.size()
&& equal(l.cbegin(), l.cend(), r.cbegin(),
[](string::value_type l1, string::value_type r1)
{ return toupper(l1) == toupper(r1); });
}
bool icasecmp(const wstring& l, const wstring& r)
{
return l.size() == r.size()
&& equal(l.cbegin(), l.cend(), r.cbegin(),
[](wstring::value_type l1, wstring::value_type r1)
{ return towupper(l1) == towupper(r1); });
}
Run Code Online (Sandbox Code Playgroud)
一个简单的函数,一个用于char的重载,另一个用于whar_t.不使用任何非标准的东西,所以在任何平台上都应该没问题.
相等比较不会考虑可变长度编码和Unicode规范化等问题,但是basic_string不支持我所知道的并且通常不是问题.
如果需要对文本进行更复杂的词典编辑操作,那么您只需使用Boost等第三方库即可.
见std::lexicographical_compare:
// lexicographical_compare example
#include <iostream> // std::cout, std::boolalpha
#include <algorithm> // std::lexicographical_compare
#include <cctype> // std::tolower
// a case-insensitive comparison function:
bool mycomp (char c1, char c2) {
return std::tolower(c1)<std::tolower(c2);
}
int main () {
char foo[] = "Apple";
char bar[] = "apartment";
std::cout << std::boolalpha;
std::cout << "Comparing foo and bar lexicographically (foo < bar):\n";
std::cout << "Using default comparison (operator<): ";
std::cout << std::lexicographical_compare(foo, foo + 5, bar, bar + 9);
std::cout << '\n';
std::cout << "Using mycomp as comparison object: ";
std::cout << std::lexicographical_compare(foo, foo + 5, bar, bar + 9, mycomp);
std::cout << '\n';
return 0;
}
Run Code Online (Sandbox Code Playgroud)
简短又好看.没有其他依赖,而不是扩展 std C lib.
strcasecmp(str1.c_str(), str2.c_str()) == 0
Run Code Online (Sandbox Code Playgroud)
如果且相等则返回true.
可能不存在,可能有类似物,等等.str1str2strcasecmpstricmpstrcmpi
示例代码:
#include <iostream>
#include <string>
#include <string.h> //For strcasecmp(). Also could be found in <mem.h>
using namespace std;
/// Simple wrapper
inline bool str_ignoreCase_cmp(std::string const& s1, std::string const& s2) {
if(s1.length() != s2.length())
return false; // optimization since std::string holds length in variable.
return strcasecmp(s1.c_str(), s2.c_str()) == 0;
}
/// Function object - comparator
struct StringCaseInsensetiveCompare {
bool operator()(std::string const& s1, std::string const& s2) {
if(s1.length() != s2.length())
return false; // optimization since std::string holds length in variable.
return strcasecmp(s1.c_str(), s2.c_str()) == 0;
}
bool operator()(const char *s1, const char * s2){
return strcasecmp(s1,s2)==0;
}
};
/// Convert bool to string
inline char const* bool2str(bool b){ return b?"true":"false"; }
int main()
{
cout<< bool2str(strcasecmp("asd","AsD")==0) <<endl;
cout<< bool2str(strcasecmp(string{"aasd"}.c_str(),string{"AasD"}.c_str())==0) <<endl;
StringCaseInsensetiveCompare cmp;
cout<< bool2str(cmp("A","a")) <<endl;
cout<< bool2str(cmp(string{"Aaaa"},string{"aaaA"})) <<endl;
cout<< bool2str(str_ignoreCase_cmp(string{"Aaaa"},string{"aaaA"})) <<endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
true
true
true
true
true
Run Code Online (Sandbox Code Playgroud)
假设你正在寻找一种方法而不是已经存在的魔法函数,坦率地说没有更好的方法.我们都可以使用有限字符集的巧妙技巧编写代码片段,但在某一天结束时,您必须转换字符.
这种转换的最佳方法是在比较之前这样做.这使您在编码方案时具有很大的灵活性,您的实际比较运算符应该是无知的.
您当然可以在自己的字符串函数或类后面"隐藏"此转换,但您仍需要在比较之前转换字符串.
我编写了一个不区分大小写的char_traits版本,用于std :: basic_string,以便在使用内置的std :: basic_string成员函数进行比较,搜索等时生成一个不区分大小写的std :: string.
换句话说,我想做这样的事情.
std::string a = "Hello, World!";
std::string b = "hello, world!";
assert( a == b );
Run Code Online (Sandbox Code Playgroud)
...哪个std :: string无法处理.这是我的新char_traits的用法:
std::istring a = "Hello, World!";
std::istring b = "hello, world!";
assert( a == b );
Run Code Online (Sandbox Code Playgroud)
......这是实施:
/* ---
Case-Insensitive char_traits for std::string's
Use:
To declare a std::string which preserves case but ignores case in comparisons & search,
use the following syntax:
std::basic_string<char, char_traits_nocase<char> > noCaseString;
A typedef is declared below which simplifies this use for chars:
typedef std::basic_string<char, char_traits_nocase<char> > istring;
--- */
template<class C>
struct char_traits_nocase : public std::char_traits<C>
{
static bool eq( const C& c1, const C& c2 )
{
return ::toupper(c1) == ::toupper(c2);
}
static bool lt( const C& c1, const C& c2 )
{
return ::toupper(c1) < ::toupper(c2);
}
static int compare( const C* s1, const C* s2, size_t N )
{
return _strnicmp(s1, s2, N);
}
static const char* find( const C* s, size_t N, const C& a )
{
for( size_t i=0 ; i<N ; ++i )
{
if( ::toupper(s[i]) == ::toupper(a) )
return s+i ;
}
return 0 ;
}
static bool eq_int_type( const int_type& c1, const int_type& c2 )
{
return ::toupper(c1) == ::toupper(c2) ;
}
};
template<>
struct char_traits_nocase<wchar_t> : public std::char_traits<wchar_t>
{
static bool eq( const wchar_t& c1, const wchar_t& c2 )
{
return ::towupper(c1) == ::towupper(c2);
}
static bool lt( const wchar_t& c1, const wchar_t& c2 )
{
return ::towupper(c1) < ::towupper(c2);
}
static int compare( const wchar_t* s1, const wchar_t* s2, size_t N )
{
return _wcsnicmp(s1, s2, N);
}
static const wchar_t* find( const wchar_t* s, size_t N, const wchar_t& a )
{
for( size_t i=0 ; i<N ; ++i )
{
if( ::towupper(s[i]) == ::towupper(a) )
return s+i ;
}
return 0 ;
}
static bool eq_int_type( const int_type& c1, const int_type& c2 )
{
return ::towupper(c1) == ::towupper(c2) ;
}
};
typedef std::basic_string<char, char_traits_nocase<char> > istring;
typedef std::basic_string<wchar_t, char_traits_nocase<wchar_t> > iwstring;
Run Code Online (Sandbox Code Playgroud)
迟到了,但这里有一个使用 的变体std::locale,因此可以正确处理土耳其语:
auto tolower = std::bind1st(
std::mem_fun(
&std::ctype<char>::tolower),
&std::use_facet<std::ctype<char> >(
std::locale()));
Run Code Online (Sandbox Code Playgroud)
为您提供一个函子,它使用活动区域设置将字符转换为小写,然后您可以使用 viastd::transform生成小写字符串:
std::string left = "fOo";
transform(left.begin(), left.end(), left.begin(), tolower);
Run Code Online (Sandbox Code Playgroud)
这也适用于wchar_t基于字符串。
这样做不使用Boost可以通过获取C字符串指针与完成c_str()和使用strcasecmp:
std::string str1 ="aBcD";
std::string str2 = "AbCd";;
if (strcasecmp(str1.c_str(), str2.c_str()) == 0)
{
//case insensitive equal
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
447257 次 |
| 最近记录: |