Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ Timesaving Techniques (2005) [eng].pdf
Скачиваний:
65
Добавлен:
16.08.2013
Размер:
8.35 Mб
Скачать

Creating the Wildcard Matching Class

331

matches both AB and AbB. So the expression con?cious matches the word conscious whether or not it included an s in that position.

Often users want to be able to use wildcards to filter data. If you give them this capability, you can save yourself a lot of time in supporting them. Appropriately used, wildcards can help make life a bit easier for everyone.

The question-mark and asterisk characters are common wildcards — but not the only ones. In the SQL language, for example, you use a percent sign (%) instead of an asterisk to match multiple characters. For this reason, when you design a class that permits wildcards in search strings, you should allow that information to be configurable. The purpose of this technique is to show you how to create a class that performs matching with wildcards. This class can be used to quickly and easily add pattern matching functionality to your application, which saves you time and effort in developing quality software that users really want.

Creating the Wildcard

Matching Class

In order to best utilize wildcard matching in your application, you should encapsulate the functionality for matching strings into a single class. That class will handle both the jobs of storing the match characters (such as an asterisk or question mark) and determining if the two strings match. Let’s develop such a class and a test driver to illustrate how it is used. Here’s how:

1. In the code editor of your choice, create a new file to hold the code for the source file of the technique.

In this example, the file is named ch55.cpp, although you can use whatever you choose.

2. Type the code from Listing 55-1 into your file.

Better yet, copy the code from the source file on this book’s companion Web site.

LISTING 55-1: THE MATCH CLASS

#include <iostream> #include <string>

using namespace std;

class Match

{

private:

char _MatchMultiple; char _MatchSingle; string _pattern; string _candidate;

protected:

bool match(const char *pat, const char *str)

{

if ( *pat == ‘\0’ ) return !*str;

else

if ( *pat == _MatchMultiple )

return match(pat+1, str) || (*str && match(pat, str+1));

(continued)

332 Technique 55: Using Wildcards

LISTING 55-1 (continued)

else

if ( *pat == _MatchSingle )

return *str && (match(pat+1, str+1) || match(pat+1, str)); return (*str == *pat) && match(pat+1, str+1);

}

public:

Match(void)

{

_MatchMultiple = ‘*’; _MatchSingle = ‘?’;

}

Match( const char *pat, const char *str )

{

_MatchMultiple = ‘*’; _MatchSingle = ‘?’; _pattern = pat; _candidate = str;

}

Match( const Match& aCopy )

{

_MatchMultiple = aCopy._MatchMultiple;

_MatchSingle

= aCopy._MatchSingle;

_pattern

=

aCopy._pattern;

_candidate

=

aCopy._candidate;

}

Match operator=( const Match& aCopy )

{

_MatchMultiple = aCopy._MatchMultiple;

_MatchSingle

= aCopy._MatchSingle;

_pattern

=

aCopy._pattern;

_candidate

=

aCopy._candidate;

return *this;

 

 

}

char Multiple(void)

{

return _MatchMultiple;

}

char Single(void)

{

return _MatchSingle;

}

void setMultiple( char mult )

{

_MatchMultiple = mult;

}

void setSingle( char single )

{

_MatchSingle = single;

}

Testing the Wildcard Matching Class

333

void setPattern( const char *pattern )

{

_pattern = pattern;

}

void setCandidate( const char *candidate )

{

_candidate = candidate;

}

string getPattern( void )

{

return _pattern;

}

string getCandidate( void )

{

return _candidate;

}

bool matches()

{

return match( _pattern.c_str(), _candidate.c_str() );

}

};

The purpose of this class is to see whether or not two strings match, including wildcards if necessary. To accomplish this, we need the following:

A multiple character wildcard

A single character wildcard

An input pattern string

The candidate match string

For example, if we wanted to allow the user to match the string Colour as well as Color so that we could check for British spellings, we would use the following:

Multiple character wildcard: An asterisk (*)

Single character wildcard: A question mark (?)

Input match string: Colo*r

Candidate match string: Either Color or

Colour

The result of this should be a positive match. To do this, we built a class that contained member variables for the match characters and strings, and routines to access those match elements. In

addition, the class contains a single method, called matches, which indicates if the input and candidate strings match.

3. Save the source code in the code editor.

Testing the Wildcard

Matching Class

After you create a class, you should create a test driver that not only ensures that your code is correct, but also shows people how to use your code.

The following steps show you how to create a test driver to illustrate various kinds of input from the user, and show how the class is intended to be used.

1. In the code editor of your choice, reopen the source file to hold the code for your test program.

In this example, I named the test program ch6_12.cpp.

334 Technique 55: Using Wildcards

2. Type the code from Listing 55-2 into your file.

Better yet, copy the code from the source file on this book’s companion Web site.

LISTING 55-2: THE WILDCARD MATCHING TEST DRIVER

string get_a_line( istream& in )

{

string retStr;

while ( !in.fail() )

{

char c; in.get(c);

if ( in.fail() ) break;

if ( c != ‘\r’ && c != ‘\n’ ) retStr += c;

if ( c == ‘\n’ ) break;

}

return retStr;

}

int main(int argc, char **argv)

{

char szPattern[ 80 ]; char szString [ 80 ]; bool done = false;

while ( !done )

{

cout << “Enter the pattern: “; string sPattern = get_a_line( cin ); if ( !sPattern.length() )

done = true;

else

{

cout << “Enter the string: “; string sString = get_a_line( cin

);

Match m(sPattern.c_str(), sString.c_str() );

if ( m.matches() ) printf(“match\n”);

else

printf(“no match\n”);

}

}

}

The test driver simply gets two strings from the user and uses wildcard matching to see if they match. The pattern string may contain optional wildcards, although the string to match may not. By utilizing the Match class that we developed in Listing 55-1, we check to see if the two strings are wildcard matches of each other.

3. Save the source code in the editor and close the editor application.

4. Compile the application, using your favorite compiler on your favorite operating system.

5. Run the application on your favorite operating system.

If you have done everything right, you should see the following session on your console window:

$ ./a.exe

Enter the pattern: A*B Enter the string: AB match

Enter the pattern: A*B Enter the string: AajkjB match

Enter the pattern: A*B Enter the string: ABC no match

Enter the pattern: A?B Enter the string: AbaB no match

Enter the pattern:

As you can see, the matching class works as advertised.

Part VIII

Utilities

56

Encoding and

 

 

Decoding Data

Technique

for the Web

 

Save Time By

Interfacing with the Internet

Encoding and decoding URLs for use on the Internet

Creating a URL Codec class

Testing that class

The World Wide Web has brought with it a host of new opportunities and a host of new problems. Most applications these days need to be Web-enabled to work directly with Web browsers or Web appli-

cations. No matter what kind of application you’re developing, odds are that the application will have to interact with the Web or with remote systems that use Web protocols.

The biggest issue in interfacing with the Internet is that of encoding. Encoding is the process of translating characters that cannot be directly used by a system into characters that can. For the World Wide Web, for example, characters such as the ampersand (&), greaterand lessthan signs (> and <), and others cannot be directly used. We need to change them into a form that the Web can use. The Web identifies addresses with a Uniform Resource Locator, better known as a URL. One of the rules of working with URLs is that they cannot contain characters such as spaces and slashes, because including them would break many existing browser applications and operating systems. Browsers assume that spaces and slashes indicate breaks in a URL, which is the standard format for Web addresses. There is no way to change the browser, so we must change the string.

The problem is that the C++ library offers no standard way to encode and decode URL strings. The technique for encoding and decoding is well known, but it is new enough that it has not yet made it into the STL or standard C++ library. For this reason, we end up reimplementing the code in each and every application that we write that needs the functionality. This is contrary to the C++ principle of “write once, reuse many times.”

Saving time is often about anticipating the needs of your application and planning for them in advance. By planning to Web-enable your code — regardless of whether you expect your application to support the Web (initially, at least) — you save a lot of time in the long-run. It makes sense, then, to create a single, reusable class that will do the encoding and decoding work, one you can insert as needed in the applications you develop. That’s what this technique is all about.