GURU Of The Week Terms 29: Single-sized String

zhaozj2021-02-16  54

GotW # 29 is not case sensitive String (Case-InSitive Strings)

Difficult: 7/10

Do you expect a string type regardless of case? Your mission is that you should choose a ready-made and accept it, or write one yourself.

problem

Write a string type in isolation, which is the same as the "String" class in the standard library, just on the case, and (non-standard, but widely used) C function stricp ():

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);

solution

Write a string type in isolation, which is the same as the "String" class in the standard library, just on the case, and (non-standard, but widely used) C function stricp ():

"How to achieve a string type of an inordant and small-sized string" is so common, so that it requires a proprietary FAQ - so discusses it in GOTW.

Note 1: StriCMP () This distinctive string comparison function is not part of the C standard, but it is available for many C compiler extensions.

Note 2: The actual meaning of "Do not vase the case" is completely dependent on your program and national language. For example, many languages ​​have no casements at all; but even so, you still need decision reread and non-reading characters equivalent, and so.

Below is the goal we expect: this GOTW guides how to implement "not distinguish cases" for standard String classes, no matter what you are in any context.

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 point is to understand what the "String class" is in the standard C . If you look at the string header file, you will see the following:

Typedef Basic_String string;

So, String is not a real class, it is a template (special) typef. Under the next, the Basic_String <> template has declared as follows, which is the whole picture:

Template

Class traits = char_traits ,

Class allocator = allocator >

Class Basic_String;

Therefore, "String" is actually "Basic_String , allocator >". We don't have to worry about the Allocator section, the key points are the char_traits section, which determines the interaction of characters and comparison operations (! Basic_string provides a commonly used comparison function to compare whether the two String objects are equal, or one less than one, and so on. The comparison function of these String classes is based on the character comparison function provided at the Char_Traits Template. In particular, the char_traits template provides the following character comparison functions: EQ () (equal), ne (), lt () (less than), compare () (compare character sequence), Find () (Search Character sequence).

If you want to have different behaviors in these operations, we have to do just provide a different char_traits template. This is the easiest way:

Struct Ci_char_Traits: Public Char_Traits

// Inherit in order to get the function we don't have to overload

{

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)

Static int COMPARE (Const Char * S1,

Const char * S2,

SIZE_T N) {

Return Memicmp (S1, S2, N);

// If your compiler provides it,

/ / Otherwise you have to achieve one yourself.

}

Static const char *

Find (const char * s, int N, char a) {

While (n--> 0 && Toupper (* s)! = TouPper (a)) {

S;

}

Return S;

}

}

Finally, take them together:

Typedef Basic_String CI_STRING;

We redefine a "ci_string", its operation is very like standard "string", just it replaces char_traits

This GOTW reveals the working principle of the Basic_String template and the flexibility to implement. If you expect these comparison functions that don't have to be implemented above, you only need to replace these 5 functions with your own code, how to meet your own programs, how to implement them.

exercise

1. Is this safe from char_traits inherited CI_CHAR_TRAITS? Why is safe or why not safe? 2. Why is the following code compile?

(WQ note, this code is already compiled by C , and it is running normally!)

Ci_String S = "ABC";

Cout << s << endl;

Tip 1: See gotw # 19.

Tip 2: Excerpt from 21.3.7.9 [lib.string.io], Basic_String Operator << operation declared as follows (it is offset):

Template

Basic_OStream &

Operator << (Basic_OStream & OS,

Const Basic_String & Strs;

(WQ note, C standard library, now "Basic_Ostream & OS" has been changed to "Ostream &", so there is no problem.)

ANSWER: Notice first that cout is actually a basic_ostream > Then we see the problem:. Operator << for basic_string is templated and all, but it's only specified for insertion into a basic_ostream with the same 'char type 'and' traits type 'as the string. That is, the standard operator << will let you output a ci_string to a basic_ostream , which is not what cout is even though ci_char_traits inherits from char_traits in The Above Solution.

(Due to errors, it is not translated.)

There are two solutions: Define CI_Strings its own inflow / outflow function, or use ".c_str ()":

Cout << S.c_str () << endl;

3. What happens when using other operations (such as , =, =) between standard String objects and CI_String objects? E.g:

String a = "aaa";

Ci_String B = "BBB";

String c = a b;

Answer: Or, define these operations of CI_String, or use ".c_str ():

String c = a b.c_str ();

转载请注明原文地址:https://www.9cbs.com/read-26724.html

New Post(0)