Search Strings for Patterns with the Match Classes

The previous article illustrated how to use the .NET Regex class to split strings, such as when you need to break a comma-delimited string into its separate components (or columns). This article covers how to search strings for patterns, where the found matches are returned via the MatchCollection and Match classes. The basic steps to using these classes are as follows:

  1. Construct a Regex object with the pattern for which you are searching.
  2. Call the Regex::Match method, passing the input value to be scanned. This method returns a boolean value indicating whether or not any matches were found.
  3. Retrieve the matches via the Regex::Matches property.
  4. Iterate the matches.

Searching for a Single Pattern Occurrence

In the following example, the code is searching a string for the first occurrence of a literal and then printing the found value (Match::Value) along with the position within the input string where that value was located (Match::Index). I've bolded the salient code for emphasis:

// Example of searching for a single literal or pattern occurrence
using namespace System::Text::RegularExpressions;
...
String* input = S"Tim, sometimes you have to accept that times are changing.";
String* pattern = S"tim";

Console::WriteLine(S"Searching '{0}' for '{1}'", input, pattern);

Regex* rex = new Regex(pattern);
Match* match = rex->Match(input);
if (match->Success)
{
  Console::WriteLine(S"Found '{0}' at position {1}",
                     match->Value,
                     __box(match->Index));

}

Searching for Multiple Matches with the MatchCollection Class

In the previous example, whereas the literal "tim" occurred several times in the input text, the code was designed to find only the first occurrence. Let's see how the code can be modified to use the MatchCollection class to enumerate all matches within a string.

In the following code, I've made several changes:

  • The Regex constructor takes a second argument of type RegexOptions that enables you to specify things, such as whether or not the search is case-sensitive. (For this example, I'm specifying RegexOptions::IgnoreCase so that the code locates all occurrences of "tim" regardless of case.)
  • The code is using the Regex::IsMatch method to first verify whether any matches are found enumerating the MatchCollection. You also can check the count of the MatchCollection object, so using either form is a subjective choice.
  • The MatchCollection object is retrieved via the Regex::Matches property. The MatchCollection object can be enumerated as any other .NET collection where the Count property indicates the number of objects held and individual objects are extracted via the collection's Item property.
String* input = S"Tim, sometimes you have to accept that times are changing.";
String* pattern = S"tim";

Console::WriteLine(S"Searching '{0}' for '{1}'", input, pattern);

Regex* rex = new Regex(pattern, RegexOptions::IgnoreCase);
if (rex->IsMatch(input))
{
  MatchCollection* matches = rex->Matches(input);		
  for (int i = 0; i  <matches->Count; i++)
  {
    Match* match = matches->Item[i];
    Console::WriteLine(S"Found '{0}' at position {1}",
                       match->Value, 
                       __box(match->Index));
  }
}

Enumerating Matches with the NextMatch Method

Did you know you can enumerate matches without the MatchCollection class? This is accomplished by using the Match::NextMatch method to enumerate through the matches of an input string. Here's an example that once again searches the same input string for occurrences of the literal "tim":

String* input = S"Tim, sometimes you have to accept that times are changing.";
String* pattern = S"tim";

Console::WriteLine(S"Searching '{0}' for '{1}'", input, pattern);

Regex* rex = new Regex(pattern, RegexOptions::IgnoreCase);
for (Match* match = rex->Match(input);
     match->Success;
     match = match->NextMatch())
{
  Console::WriteLine(S"Found '{0}' at position {1}",
                     match->Value, 
                     __box(match->Index));
}

Looking Ahead

So far, you've covered the basics of splitting strings and using the Match/MatchCollection classes. Future articles continue in the .NET implementation of regular expressions by delving into how to form regular expression patterns to find what you're looking for and the topics of groups and captures.



About the Author

Tom Archer - MSFT

I am a Program Manager and Content Strategist for the Microsoft MSDN Online team managing the Windows Vista and Visual C++ developer centers. Before being employed at Microsoft, I was awarded MVP status for the Visual C++ product. A 20+ year veteran of programming with various languages - C++, C, Assembler, RPG III/400, PL/I, etc. - I've also written many technical books (Inside C#, Extending MFC Applications with the .NET Framework, Visual C++.NET Bible, etc.) and 100+ online articles.

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • When individual departments procure cloud service for their own use, they usually don't consider the hazardous organization-wide implications. Read this paper to learn best practices for setting up an internal, IT-based cloud brokerage function that service the entire organization. Find out how this approach enables you to retain top-down visibility and control of network security and manage the impact of cloud traffic on your WAN.

  • Traditional approaches to application modernization, either manual rewrite or auto-migration tools, have been proven time and again as inefficient. Rewrite needs scarce dev skills, is slow, risky and costly; auto-migration is what Verccio Dale of Gartner defines as "a pig with a lipstick, is still a pig." Are there alternatives? Find out, download this short practical guide now!

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date