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

}

};

#endif // ICHAR_TRAITS_H ///:~

If we typedef an istring class like this:

typedef basic_string<char, ichar_traits, allocator<char> > istring;

Then this istring will act like an ordinary string in every way, except that it will make all comparisons without respect to case. Here’s an example:

//: C01:ICompare.cpp #include "ichar_traits.h" #include <string> #include <iostream>

using namespace std;

typedef basic_string<char, ichar_traits, allocator<char> > istring;

int main() {

// The same letters except for case: istring first = "tHis";

istring second = "ThIS";

cout << first.compare(second) << endl; } ///:~

The output from the program is “0”, indicating that the strings compare as equal. This is just a simple example – in order to make istring fully equivalent to string, we’d have to create the other functions necessary to support the new istring type.

A string application

My friend Daniel (who designed the cover and page layout for this book) does a lot of work with Web pages. One tool he uses creates a “site map” consisting of a Java applet to display the map and an HTML tag that invoked the applet and provided it with the necessary data to create the map. Daniel wanted to use this data to create an ordinary HTML page (sans applet) that would contain regular links as the site map. The resulting program turns out to be a nice practical application of the string class, so it is presented here.

The input is an HTML file that contains the usual stuff along with an applet tag with a parameter that begins like this:

<param name="source_file" value="

Chapter 14: Templates & Container Classes

58

The rest of the line contains encoded information about the site map, all combined into a single line (it’s rather long, but fortunately string objects don’t care). Each entry may or may not begin with a number of ‘#’ signs; each of these indicates one level of depth. If no ‘#’ sign is present the entry will be considered to be at level one. After the ‘#’ is the text to be displayed on the page, followed by a ‘%’ and the URL to use as the link. Each entry is terminated by a ‘*’. Thus, a single entry in the line might look like this:

###|Useful Art%./Build/useful_art.html*

The ‘|’ at the beginning is an artifact that needs to be removed.

My solution was to create an Item class whose constructor would take input text and create an object that contains the text to be displayed, the URL and the level. The objects essentially parse themselves, and at that point you can read any value you want. In main( ), the input file is opened and read until the line contains the parameter that we’re interested in. Everything but the site map codes are stripped away from this string, and then it is parsed into Item objects:

//: C01:SiteMapConvert.cpp

//Using strings to create a custom conversion

//program that generates HTML output

#include "../require.h" #include <iostream> #include <fstream> #include <string> #include <cstdlib> using namespace std;

class Item { string id, url; int depth;

string removeBar(string s) { if(s[0] == '|')

return s.substr(1); else return s;

}

public:

Item(string in, int& index) : depth(0) { while(in[index] == '#' && index < in.size()){

depth++;

index++;

}

// 0 means no '#' marks were found: if(depth == 0) depth = 1;

while(in[index] != '%' && index < in.size())

Chapter 14: Templates & Container Classes

59

id += in[index++]; id = removeBar(id);

index++; // Move past '%'

while(in[index] != '*' && index < in.size()) url += in[index++];

url = removeBar(url); index++; // To move past '*'

}

string identifier() { return id; } string path() { return url; }

int level() { return depth; }

};

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

"usage: SiteMapConvert inputfilename"); ifstream in(argv[1]);

assure(in, argv[1]);

ofstream out("plainmap.html"); string line;

while(getline(in, line)) { if(line.find("<param name=\"source_file\"")

!= string::npos) {

//Extract data from start of sequence

//until the terminating quote mark: line = line.substr(line.find("value=\"")

+string("value=\"").size()); line = line.substr(0,

line.find_last_of("\"")); int index = 0;

while(index < line.size()) { Item item(line, index);

string startLevel, endLevel; if(item.level() == 1) {

startLevel = "<h1>"; endLevel = "</h1>";

}else

for(int i = 0; i < item.level(); i++) for(int j = 0; j < 5; j++)

out << " ";

string htmlLine = "<a href=\""

+item.path() + "\">"

+item.identifier() + "</a><br>";

Chapter 14: Templates & Container Classes

60

out << startLevel << htmlLine << endLevel << endl;

}

break; // Out of while loop

}

}

} ///:~

Item contains a private member function removeBar( ) that is used internally to strip off the leading bars, if they appear.

The constructor for Item initializes depth to 0 to indicate that no ‘#’ signs were found yet; if none are found then it is assumed the Item should be displayed at level one. Each character in the string is examined using operator[ ] to find the depth, id and url values. The other member functions simply return these values.

After opening the files, main( ) uses string::find( ) to locate the line containing the site map data. At this point, substr( ) is used in order to strip off the information before and after the site map data. The subsequent while loop performs the parsing, but notice that the value index is passed by reference into the Item constructor, and that constructor increments index as it parses each new Item, thus moving forward in the sequence.

If an Item is at level one, then an HTML h1 tag is used, otherwise the elements are indented using HTML non-breaking spaces. Note in the initialization of htmlLine how easy it is to construct a string – you can just combine quoted character arrays and other string objects using operator+.

When the output is written to the destination file, startLevel and endLevel will only produce results if they have been given any value other than their default initialization values.

Summary

C++ string objects provide developers with a number of great advantages over their C counterparts. For the most part, the string class makes referring to strings through the use of character pointers unnecessary. This eliminates an entire class of software defects that arise from the use of uninitialized and incorrectly valued pointers. C++ strings dynamically and transparently grow their internal data storage space to accommodate increases in the size of the string data. This means that when the data in a string grows beyond the limits of the memory initially allocated to it, the string object will make the memory management calls that take space from and return space to the heap. Consistent allocation schemes prevent memory leaks and have the potential to be much more efficient than “roll your own” memory management.

The string class member functions provide a fairly comprehensive set of tools for creating, modifying, and searching in strings. string comparisons are always case sensitive, but you can work around this by copying string data to C style null terminated strings and using case

Chapter 14: Templates & Container Classes

61

Соседние файлы в предмете Численные методы
  • #
    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