Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
B.Eckel - Thinking in C++, Vol.2, 2nd edition.pdf
Скачиваний:
50
Добавлен:
08.05.2013
Размер:
2.09 Mб
Скачать

cout << "removed";

cout << "<br>Thank you</H2>" << endl; } ///:~

Again, all the CGI work is done by the CGImap. From then on it’s a matter of pulling the fields out and looking at them, then deciding what to do about it, which is easy because of the way you can index into a map and also because of the tools available for standard strings. Here, most of the programming has to do with checking for a valid email address. Then a file name is created with the email address as the name and “.add” or “.remove” as the extension, and the email address is placed in the file.

Maintaining your list

Once you have a list of names to add, you can just paste them to end of your list. However, you might get some duplicates so you need a program to remove those. Because your names may differ only by upper and lowercase, it’s useful to create a tool that will read a list of names from a file and place them into a container of strings, forcing all the names to lowercase as it does:

//: C10:readLower.h

//Read a file into a container of string,

//forcing each line to lower case. #ifndef READLOWER_H

#define READLOWER_H #include "../require.h" #include <iostream> #include <fstream> #include <string> #include <algorithm> #include <cctype>

inline char downcase(char c) {

using namespace std; // Compiler bug return tolower(c);

}

std::string lcase(std::string s) { std::transform(s.begin(), s.end(),

s.begin(), downcase); return s;

}

template<class SContainer>

void readLower(char* filename, SContainer& c) { std::ifstream in(filename);

Appendix B: Programming Guidelines

553

assure(in, filename); const int sz = 1024; char buf[sz];

while(in.getline(buf, sz)) // Force to lowercase:

c.push_back(string(lcase(buf)));

}

#endif // READLOWER_H ///:~

Since it’s a template, it will work with any container of string that supports push_back( ). Again, you may want to change the above to the form readln(in, s) instead of using a fixedsized buffer, which is more fragile.

Once the names are read into the list and forced to lowercase, removing duplicates is trivial:

//: C10:RemoveDuplicates.cpp

// Remove duplicate names from a mailing list #include "readLower.h"

#include "../require.h" #include <vector> #include <algorithm> using namespace std;

int main(int argc, char* argv[]) { requireArgs(argc, 2); vector<string> names; readLower(argv[1], names);

long before = names.size();

//You must sort first for unique() to work: sort(names.begin(), names.end());

//Remove adjacent duplicates: unique(names.begin(), names.end()); long removed = before - names.size(); ofstream out(argv[2]);

assure(out, argv[2]); copy(names.begin(), names.end(),

ostream_iterator<string>(out,"\n")); cout << removed << " names removed" << endl;

}///:~

A vector is used here instead of a list because sorting requires random-access which is much faster in a vector. (A list has a built-in sort( ) so that it doesn’t suffer from the performance that would result from applying the normal sort( ) algorithm shown above).

Appendix B: Programming Guidelines

554

The sort must be performed so that all duplicates are adjacent to each other. Then unique( ) can remove all the adjacent duplicates. The program also keeps track of how many duplicate names were removed.

When you have a file of names to remove from your list, readLower( ) comes in handy again:

//: C10:RemoveGroup.cpp

// Remove a group of names from a list #include "readLower.h"

#include "../require.h" #include <list>

using namespace std;

typedef list<string> Container;

int main(int argc, char* argv[]) { requireArgs(argc, 3);

Container names, removals; readLower(argv[1], names); readLower(argv[2], removals); long original = names.size();

Container::iterator rmit = removals.begin(); while(rmit != removals.end())

names.remove(*rmit++); // Removes all matches ofstream out(argv[3]);

assure(out, argv[3]); copy(names.begin(), names.end(),

ostream_iterator<string>(out,"\n")); long removed = original - names.size();

cout << "On removal list: " << removals.size()

<<"\n Removed: " << removed << endl;

}///:~

Here, a list is used instead of a vector (since readLower( ) is a template, it adapts). Although there is a remove( ) algorithm that can be applied to containers, the built-in list::remove( ) seems to work better. The second command-line argument is the file containing the list of names to be removed. An iterator is used to step through that list, and the list::remove( ) function removes every instance of each name from the master list. Here, the list doesn’t need to be sorted first.

Unfortunately, that’s not all there is to it. The messiest part about maintaining a mailing list is the bounced messages. Presumably, you’ll just want to remove the addresses that produce bounces. If you can combine all the bounced messages into a single file, the following program has a pretty good chance of extracting the email addresses; then you can use RemoveGroup to delete them from your list.

Appendix B: Programming Guidelines

555

//: C10:ExtractUndeliverable.cpp

//Find undeliverable names to remove from

//mailing list from within a mail file

//containing many messages

#include "../require.h" #include <cstdio> #include <string> #include <set>

using namespace std;

char* start_str[] = { "following address", "following recipient", "following destination",

"undeliverable to the following", "following invalid",

};

char* continue_str[] = { "Message-ID",

"Please reply to",

};

//The in() function allows you to check whether

//a string in this set is part of your argument. class StringSet {

char** ss; int sz;

public:

StringSet(char** sa, int sza):ss(sa),sz(sza) {} bool in(char* s) {

for(int i = 0; i < sz; i++) if (strstr(s, ss[i]) != 0)

return true; return false;

}

};

//Calculate array length:

#define ALEN(A) ((sizeof A)/(sizeof *A))

StringSet

starts(start_str, ALEN(start_str)),

Appendix B: Programming Guidelines

556

continues(continue_str, ALEN(continue_str));

int main(int argc, char* argv[]) { requireArgs(argc, 2,

"Usage:ExtractUndeliverable infile outfile"); FILE* infile = fopen(argv[1], "rb");

FILE* outfile = fopen(argv[2], "w"); require(infile != 0); require(outfile != 0); set<string> names;

const int sz = 1024; char buf[sz];

while(fgets(buf, sz, infile) != 0) { if(starts.in(buf)) {

puts(buf);

while(fgets(buf, sz, infile) != 0) { if(continues.in(buf)) continue; if(strstr(buf, "---") != 0) break;

const char* delimiters= " \t<>():;,\n\""; char* name = strtok(buf, delimiters); while(name != 0) {

if(strstr(name, "@") != 0) names.insert(string(name));

name = strtok(0, delimiters);

}

}

}

}

set<string>::iterator i = names.begin(); while(i != names.end())

fprintf(outfile, "%s\n", (*i++).c_str()); } ///:~

The first thing you’ll notice about this program is that contains some C functions, including C I/O. This is not because of any particular design insight. It just seemed to work when I used the C elements, and it started behaving strangely with C++ I/O. So the C is just because it works, and you may be able to rewrite the program in more “pure C++” using your C++ compiler and produce correct results.

A lot of what this program does is read lines looking for string matches. To make this convenient, I created a StringSet class with a member function in( ) that tells you whether any of the strings in the set are in the argument. The StringSet is initialized with a constant two-dimensional of strings and the size of that array. Although the StringSet makes the code easier to read, it’s also easy to add new strings to the arrays.

Appendix B: Programming Guidelines

557

Соседние файлы в предмете Численные методы
  • #
    08.05.20133.99 Mб22A.Menezes, P.van Oorschot,S.Vanstone - HANDBOOK OF APPLIED CRYPTOGRAPHY.djvu
  • #
  • #
    08.05.20135.91 Mб24B.Eckel - Thinking in Java, 3rd edition (beta).pdf
  • #
  • #
    08.05.20136.09 Mб17D.MacKay - Information Theory, Inference, and Learning Algorithms.djvu
  • #
    08.05.20133.85 Mб15DIGITAL Visual Fortran ver.5.0 - Programmers Guide to Fortran.djvu
  • #
    08.05.20131.84 Mб12E.A.Lee, P.Varaiya - Structure and Interpretation of Signals and Systems.djvu