Lots of programmers have been familiar with
some routines for string object, such as length, substring, find,
charAt, toLowerCase, toUpperCase, trim, equalsIgnoreCase, startsWith,
endsWith, parseInt, toString, split, and so on.
Now, if you are using STL and its string class std::string, how to do something which above routines do?
Of course, std::string supplies some methods to implements some routines above. They are,
length()
, get the length of the string.
substr()
, get a substring of the string.
at()
/operator []
, get the char at specified location in the string.
find
/rfind()
, search a string in a forward/backward direction for a substring.
find_first_of()
, find the first character that is any of specified characters.
find_first_not_of()
, find the first character that is not any of specified characters.
find_last_of()
, find the last character that is any of specified characters.
find_last_not_of()
, find the last character that is not any of specified characters.
Please refer document for more std::string
's methods
Some routines are not implemented as std::string's methods, but we
can find way in algorithm.h to do that. Of course, the existed methods
of std::string are also used to implement them.
Transform a string to upper/lower case
Collapse
std::transform(str.begin(), str.end(), str.begin(), tolower);
std::transform(str.begin(), str.end(), str.begin(), toupper);
Please refer document for detail of std::transform function
Trim spaces beside a string
Trim left spaces
Collapse
string::iterator i;
for (i = str.begin(); i != str.end(); i++) {
if (!isspace(*i)) {
break;
}
}
if (i == str.end()) {
str.clear();
} else {
str.erase(str.begin(), i);
}
Trim right spaces
Collapse
string::iterator i;
for (i = str.end() - 1; ;i--) {
if (!isspace(*i)) {
str.erase(i + 1, str.end());
break;
}
if (i == str.begin()) {
str.clear();
break;
}
}
Trim two-sided spaces
Trim left spaces then trim right spaces. Thus two-sided spaces are trimed.
Create string by repeating character or substring
If you want create a string by repeating substring, you must use loop to implement it.
Collapse
string repeat(const string& str, int n) {
string s;
for (int i = 0; i < n; i++) {
s += str;
}
return s;
}
But if you need just to repeat character, std::string has a constructor.
Collapse
string repeat(char c, int n) {
return string(n, c);
}
Compare ignore case
It's funny. We should copy the two strings which attend compare.
Then transform all of them to lower case. At last, just compare the two
lower case strings.
StartsWith and EndsWith
StartsWith
Collapse
str.find(substr) == 0;
If result is true
, the str
starts with substr
.
EndsWith
Collapse
size_t i = str.rfind(substr);
return (i != string::npos) && (i == (str.length() - substr.length()));
If result is true
, the str
ends with substr
There is another way to do that. Just get left substring or right
substring to compare. Because I don't want to calculate if string's
length is enough, so I use find and rfind to do that.
Parse number/bool from a string
For these routines, atoi
, atol
and some other C functions are OK. But I want use C++ way to do. So I choose std::istringstream
. the class is in sstream.h.
A template function can do most excludes bool value.
Collapse
template<class T> parseString(const std::string& str) {
T value;
std::istringstream iss(str);
iss >> value;
return value;
}
The template function can parse 0 as false
and other number as true
. But it cannot parse "false"
as false
and "true"
as true
. So I write a special function.
Collapse
template<bool>
bool parseString(const std::string& str) {
bool value;
std::istringstream iss(str);
iss >> boolalpha >> value;
return value;
}
As you saw, I pass a std::boolalpha
flag to the input stream, then the input stream can recognize literal bool value.
It is possible to use a similar way to parse hex string. This time I should pass a std::hex
flag to the stream.
Collapse
template<class T> parseHexString(const std::string& str) {
T value;
std::istringstream iss(str);
iss >> hex >> value;
return value;
}
To string routines
Like parsing from string, I will use std::ostringstream
to get string from other kinds of value. The class is also in sstream.h. The relative 3 functions are followed.
Collapse
template<class T> std::string toString(const T& value) {
std::ostringstream oss;
oss << value;
return oss.str();
}
string toString(const bool& value) {
ostringstream oss;
oss << boolalpha << value;
return oss.str();
}
template<class T> std::string toHexString(const T& value, int width) {
std::ostringstream oss;
oss << hex;
if (width > 0) {
oss << setw(width) << setfill('0');
}
oss << value;
return oss.str();
}
Do you take note of setw
and setfill
? They are still flags which need an argument. std::setw
allow the output thing in the stream occupy fixed width. If itself length is not enough, default uses space to fill. std::setfill
is used to change the spaceholder. If you want control the alignment, there are std::left
and std::right
flags.
Oh, I forgot to tell you, setw and setfill need iomanip.h header file.
Split
and tokenizer
I think split function should be implemented with a tokenizer. So I write a tokenizer at first. We can use find_first_of
and find_first_not_of
methods to get each token. Follows is nextToken method of Tokenizer class.
Collapse
bool Tokenizer::nextToken(const std::string& delimiters) {
size_t i = m_String.find_first_not_of(delimiters, m_Offset);
if (i == string::npos) {
m_Offset = m_String.length();
return false;
}
size_t j = m_String.find_first_of(delimiters, i);
if (j == string::npos) {
m_Token = m_String.substr(i);
m_Offset = m_String.length();
return true;
}
m_Token = m_String.substr(i, j - i);
m_Offset = j;
return true;
}
The whole Tokenizer is in the source code archive. You can download
it at above. All other functions are still in the source code files.
License