int root = int(sqrt(double(p)));
for (int i = 2; i <= root; ++i)
if (p % i == 0) return false;
return true;
}
void findPrimes() {
// By definition neither 0 nor 1 is prime.
// Change these elements to "N" for Not Prime
sieveChars.replace(0, 2, "NN");
// Walk through the array:
size_t sieveSize = sieveChars.size();
int root = int(sqrt(double(sieveSize)));
for (int i = 2; i <= root; ++i)
// Find all the multiples:
for (size_t factor = 2; factor * i < sieveSize;
++factor)
sieveChars[factor * i] = 'N';
}
void testPrimes() {
size_t i = sieveChars.find('P');
while (i != string::npos) {
test_(isPrime(i++));
i = sieveChars.find('P', i);
}
i = sieveChars.find_first_not_of('P');
while (i != string::npos) {
test_(!isPrime(i++));
i = sieveChars.find_first_not_of('P', i);
}
}
};
int main() {
SieveTest t;
t.run();
return t.report();
} ///:~
The find( )function allows you to walk forward through a string, detecting multiple occurrences of a character or a group of characters, and find_first_not_of( )allows you to find other characters or substrings .
There are no functions in the stringclass to change the case of a string, but you can easily create these functions using the Standard C library functions toupper( )and tolower( ), which change the case of one character at a time. The following example illustrates a case-insensitive search: .
//: C03:Find.cpp
//{L} ../TestSuite/Test
#include
#include
#include
#include "../TestSuite/Test.h"
using namespace std;
// Make an uppercase copy of s
string upperCase(const string& s) {
string upper(s);
for(size_t i = 0; i < s.length(); ++i)
upper[i] = toupper(upper[i]);
return upper;
}
// Make a lowercase copy of s
string lowerCase(const string& s) {
string lower(s);
for(size_t i = 0; i < s.length(); ++i)
lower[i] = tolower(lower[i]);
return lower;
}
class FindTest : public TestSuite::Test {
string chooseOne;
public:
FindTest() : chooseOne("Eenie, Meenie, Miney, Mo") {}
void testUpper() {
string upper = upperCase(chooseOne);
const string LOWER = "abcdefghijklmnopqrstuvwxyz";
test_(upper.find_first_of(LOWER) == string::npos);
}
void testLower() {
string lower = lowerCase(chooseOne);
const string UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
test_(lower.find_first_of(UPPER) == string::npos);
}
void testSearch() {
// Case sensitive search
size_t i = chooseOne.find("een");
test_(i == 8);
// Search lowercase:
string test = lowerCase(chooseOne);
i = test.find("een");
test_(i == 0);
i = test.find("een", ++i);
test_(i == 8);
i = test.find("een", ++i);
test_(i == string::npos);
// Search uppercase:
test = upperCase(chooseOne);
i = test.find("EEN");
test_(i == 0);
i = test.find("EEN", ++i);
test_(i == 8);
i = test.find("EEN", ++i);
test_(i == string::npos);
}
void run() {
testUpper();
testLower();
testSearch();
}
};
int main() {
FindTest t;
t.run();
return t.report();
} ///:~
Both the upperCase( )and lowerCase( )functions follow the same form: they make a copy of the argument stringand change the case. The NewFind.cppprogram isn’t the best solution to the case-sensitivity problem, so we’ll revisit it when we examine stringcomparisons .
Sometimes it’s necessary to search through a stringfrom end to beginning, if you need to find the data in "last in / first out" order. The string member function rfind( )handles this job .
//: C03:Rparse.cpp
//{L} ../TestSuite/Test
#include
#include
#include "../TestSuite/Test.h"
using namespace std;
class RparseTest : public TestSuite::Test {
// To store the words:
vector strings;
public:
void parseForData() {
// The ';' characters will be delimiters
string s("now.;sense;make;to;going;is;This");
// The last element of the string:
int last = s.size();
// The beginning of the current word:
int current = s.rfind(';');
// Walk backward through the string:
while(current != string::npos){
// Push each word into the vector.
// Current is incremented before copying to
// avoid copying the delimiter:
++current;
strings.push_back(
s.substr(current, last - current));
// Back over the delimiter we just found,
// and set last to the end of the next word:
current -= 2;
last = current + 1;
// Find the next delimiter
current = s.rfind(';', current);
}
// Pick up the first word - it's not
// preceded by a delimiter
strings.push_back(s.substr(0, last));
}
void testData() {
// Test order them in the new order:
test_(strings[0] == "This");
test_(strings[1] == "is");
test_(strings[2] == "going");
test_(strings[3] == "to");
test_(strings[4] == "make");
test_(strings[5] == "sense");
test_(strings[6] == "now.");
string sentence;
for(int i = 0; i < strings.size() - 1; i++)
sentence += strings[i] += " ";
// Manually put last word in to avoid an extra space
sentence += strings[strings.size() - 1];
test_(sentence == "This is going to make sense now.");
}
void run() {
parseForData();
testData();
}
};
int main() {
RparseTest t;
t.run();
return t.report();
} ///:~
The string member function rfind( )backs through the string looking for tokens and reporting the array index of matching characters or string::nposif it is unsuccessful .
Finding first/last of a set of characters
The find_first_of( )and find_last_of( )member functions can be conveniently put to work to create a little utility that will strip whitespace characters from both ends of a string. Notice that it doesn’t touch the original string, but instead returns a new string: .
//: C03:Trim.h
#ifndef TRIM_H
#define TRIM_H
#include
// General tool to strip spaces from both ends:
inline std::string trim(const std::string& s) {
if(s.length() == 0)
return s;
int beg = s.find_first_not_of(" \a\b\f\n\r\t\v");
int end = s.find_last_not_of(" \a\b\f\n\r\t\v");
if(beg == std::string::npos) // No non-spaces
return "";
return std::string(s, beg, end - beg + 1);
}
#endif // TRIM_H ///:~
The first test checks for an empty string; in that case, no tests are made, and a copy is returned. Notice that once the end points are found, the stringconstructor builds a new stringfrom the old one, giving the starting count and the length .
Testing such a general-purpose tool needs to be thorough: .
//: C03:TrimTest.cpp
//{L} ../TestSuite/Test
#include
#include "Trim.h"
#include "../TestSuite/Test.h"
using namespace std;
string s[] = {
" \t abcdefghijklmnop \t ",
"abcdefghijklmnop \t ",
" \t abcdefghijklmnop",
"a", "ab", "abc", "a b c",
" \t a b c \t ", " \t a \t b \t c \t ",
"\t \n \r \v \f",
Читать дальше