?? gotw29a.txt
字號:
From: herbs@cntc.com (Herb Sutter)Subject: Guru of the Week #29: SolutionDate: 22 Jan 1998 00:00:00 GMTMessage-ID: <6a8q26$9qa@netlab.cs.rpi.edu>Newsgroups: comp.lang.c++.moderated .--------------------------------------------------------------------. | Guru of the Week problems and solutions are posted regularly on | | news:comp.lang.c++.moderated. For past problems and solutions | | see the GotW archive at http://www.cntc.com. | | Is there a topic you'd like to see covered? mailto:herbs@cntc.com | `--------------------------------------------------------------------'_______________________________________________________GotW #29: StringsDifficulty: 7 / 10_______________________________________________________>Write a ci_string class which is identical to the>standard 'string' class, but is case-insensitive in the>same way as the C function stricmp():The "how can I make a case-insensitive string?"question is so common that it probably deserves its ownFAQ -- hence this issue of GotW.Note 1: The stricmp() case-insensitive stringcomparison function is not part of the C standard, butit is a common extension on many C compilers.Note 2: What "case insensitive" actually means dependsentirely on your application and language. Forexample, many languages do not have "cases" at all, andfor languages that do you have to decide whether youwant accented characters to compare equal to unaccentedcharacters, and so on. This GotW provides guidance onhow to implement case-insensitivity for standardstrings in whatever sense applies to your particularsituation.Here's what we want to achieve:> ci_string s( "AbCdE" );>> // case insensitive> assert( s == "abcde" );> assert( s == "ABCDE" );>> // still case-preserving, of course> assert( strcmp( s.c_str(), "AbCdE" ) == 0 );> assert( strcmp( s.c_str(), "abcde" ) != 0 );The key here is to understand what a "string" actuallyis in standard C++. If you look in your trusty stringheader, you'll see something like this: typedef basic_string<char> string;So string isn't really a class... it's a typedef of atemplate. In turn, the basic_string<> template isdeclared as follows, in all its glory: template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> > class basic_string;So "string" really means "basic_string<char,char_traits<char>, allocator<char> >". We don't needto worry about the allocator part, but the key here isthe char_traits part because char_traits defines howcharacters interact and compare(!).basic_string supplies useful comparison functions thatlet you compare whether a string is equal to another,less than another, and so on. These string comparisonsfunctions are built on top of character comparisonfunctions supplied in the char_traits template. Inparticular, the char_traits template supplies charactercomparison functions named eq(), ne(), and lt() forequality, inequality, and less-than comparisons, andcompare() and find() functions to compare and searchsequences of characters.If we want these to behave differently, all we have todo is provide a different char_traits template! Here'sthe easiest way: struct ci_char_traits : public char_traits<char> // just inherit all the other functions // that we don't need to override { static bool eq( char c1, char c2 ) { return tolower(c1) == tolower(c2); } static bool ne( char c1, char c2 ) { return tolower(c1) != tolower(c2); } static bool lt( char c1, char c2 ) { return tolower(c1) < tolower(c2); } static int compare( const char* s1, const char* s2, size_t n ) { return strnicmp( s1, s2, n ); // if available on your compiler, // otherwise you can roll your own } static const char* find( const char* s, int n, char a ) { while( n-- > 0 && tolower(*s) != tolower(a) ) { ++s; } return s; } };And finally, the key that brings it all together: typedef basic_string<char, ci_char_traits> ci_string;All we've done is created a typedef named "ci_string"which operates exactly like the standard "string",except that it uses ci_char_traits instead ofchar_traits<char> to get its character comparisonrules. Since we've handily made the ci_char_traitsrules case-insensitive, we've made ci_string itselfcase-insensitive without any further surgery -- thatis, we have a case-insensitive string without havingtouched basic_string at all!This GotW should give you a flavour for how thebasic_string template works and how flexible it is inpractice. If you want different comparisons than theones stricmp() and tolower() give you, just replace thefive functions shown above with your own code thatperforms character comparisons the way that'sappropriate in your particular application.Exercise for the reader:Is it safe to inherit ci_char_traits fromchar_traits<char> this way? Why or why not?
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -