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

  • Live Event Date: October 29, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Are you interested in building a cognitive application using the power of IBM Watson? Need a platform that provides speed and ease for rapidly deploying this application? Join Chris Madison, Watson Solution Architect, as he walks through the process of building a Watson powered application on IBM Bluemix. Chris will talk about the new Watson Services just released on IBM bluemix, but more importantly he will do a step by step cognitive …

  • QA teams don't have time to test everything yet they can't afford to ship buggy code. Learn how Coverity can help organizations shrink their testing cycles and reduce regression risk by focusing their manual and automated testing based on the impact of change.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds