dirk/C++/glibmm/patternSpec


Ravensburg, 10-02-08

patternSpec – Glob-style Pattern Matching

Actually, I was looking for a possibility to search directories for files with a certain pattern. Instead of the desired functions/classes, I found the Glib::PatternSpec class. Although this wasn't my actual intention, I gave it a try having in mind just another problem I had to solve in my current professional development.

One of my main issues: does the pattern matching accept slashes ('/') in place-holder expressions like '*'. If so, I could use it to process certain property rules in the manner of X11 resource files.

Glob-Style vs. Regular Expressions

Glob-style pattern matching is easy to use and for most users wellknown due to daily file work. Regular expressions are much more powerful but only few people know how it works. IMHO user friendly software should left the choice to the user.

Source Code

Text FilepatternSpec.cc
/** @file sample for Glib::PatternSpec
 *
 * Last CVS checkin:
 * $Date: $
 * $Author: scheff $
 */

/**************************************************************************/

// standard C/C++ header:

#include <iostream>
#include <string>

// Gnome header:

#include <glibmm/init.h>
#include <glibmm/pattern.h>

using namespace std;

/**************************************************************************/

/** waits for user confirm.
 *
 * @param action text with next action
 */
static void pause(const char *action)
{
  cout << "Press [ENTER] to " << action << ": " << flush;
  string str; getline(cin, str);
}

/** provides the main function of application.
 *
 * @param argc number of command line arguments
 * @param argv pointer to array of pointers to strings with command line
 *        arguments
 * @return 0 ... application exited regularly\n
 *         else ... execution of application aborted
 */
int main(int argc, char *argv[])
{
  Glib::init();
  pause("start");
  // sample data

  const char *patterns[] = {
    "*",
    "Base*",
    "Base/*",
    "*Base*",
    "Robot*",
    "*Robot*",
    "*/Robot",
    "*/Robot*",
    "*/Robot/*"
  };
  int m = sizeof patterns / sizeof patterns[0];
  const char *samples[] = {
    "",
    "Base",
    "Base/Resource",
    "Base/Resource/Robot",
    "Base/Resource/Robot/KUKA",
    "Base/Resource/Robot/KUKA/KR360"
  };
  int n = sizeof samples / sizeof samples[0];
  // for each pattern and each sample do:

  for (int i = 0; i < m; ++i) {
    Glib::PatternSpec patternSpec(patterns[i]);
    cout << "Pattern: '" << patterns[i] << "':" << endl;
    for (int j = 0; j < n; ++j) {
      const char *sample = samples[j];
      cout << "  Check '" << sample << "':" << endl
        << "    " << (patternSpec.match(sample) ? "OK." : "Not matching.")
        << endl;
    }
    // wait for confirm

    pause("continue");
  }
  // done

  pause("finish");
  return 0;
}

I compiled this sample on Linux with:

                                                                                
> g++ -o patternSpec `pkg-config glibmm-2.4 --cflags --libs` patternSpec.cc> 

Output

Console:
                                                                                
Press [ENTER] to start: ↵
Pattern: '*':
  Check '':
    OK.
  Check 'Base':
    OK.
  Check 'Base/Resource':
    OK.
  Check 'Base/Resource/Robot':
    OK.
  Check 'Base/Resource/Robot/KUKA':
    OK.
  Check 'Base/Resource/Robot/KUKA/KR360':
    OK.
Press [ENTER] to continue: ↵
Pattern: 'Base*':
  Check '':
    Not matching.
  Check 'Base':
    OK.
  Check 'Base/Resource':
    OK.
  Check 'Base/Resource/Robot':
    OK.
  Check 'Base/Resource/Robot/KUKA':
    OK.
  Check 'Base/Resource/Robot/KUKA/KR360':
    OK.
Press [ENTER] to continue: ↵
Pattern: 'Base/*':
  Check '':
    Not matching.
  Check 'Base':
    Not matching.
  Check 'Base/Resource':
    OK.
  Check 'Base/Resource/Robot':
    OK.
  Check 'Base/Resource/Robot/KUKA':
    OK.
  Check 'Base/Resource/Robot/KUKA/KR360':
    OK.
Press [ENTER] to continue: ↵
Pattern: '*Base*':
  Check '':
    Not matching.
  Check 'Base':
    OK.
  Check 'Base/Resource':
    OK.
  Check 'Base/Resource/Robot':
    OK.
  Check 'Base/Resource/Robot/KUKA':
    OK.
  Check 'Base/Resource/Robot/KUKA/KR360':
    OK.
Press [ENTER] to continue: ↵
Pattern: 'Robot*':
  Check '':
    Not matching.
  Check 'Base':
    Not matching.
  Check 'Base/Resource':
    Not matching.
  Check 'Base/Resource/Robot':
    Not matching.
  Check 'Base/Resource/Robot/KUKA':
    Not matching.
  Check 'Base/Resource/Robot/KUKA/KR360':
    Not matching.
Press [ENTER] to continue: ↵
Pattern: '*Robot*':
  Check '':
    Not matching.
  Check 'Base':
    Not matching.
  Check 'Base/Resource':
    Not matching.
  Check 'Base/Resource/Robot':
    OK.
  Check 'Base/Resource/Robot/KUKA':
    OK.
  Check 'Base/Resource/Robot/KUKA/KR360':
    OK.
Press [ENTER] to continue: ↵
Pattern: '*/Robot':
  Check '':
    Not matching.
  Check 'Base':
    Not matching.
  Check 'Base/Resource':
    Not matching.
  Check 'Base/Resource/Robot':
    OK.
  Check 'Base/Resource/Robot/KUKA':
    Not matching.
  Check 'Base/Resource/Robot/KUKA/KR360':
    Not matching.
Press [ENTER] to continue: ↵
Pattern: '*/Robot*':
  Check '':
    Not matching.
  Check 'Base':
    Not matching.
  Check 'Base/Resource':
    Not matching.
  Check 'Base/Resource/Robot':
    OK.
  Check 'Base/Resource/Robot/KUKA':
    OK.
  Check 'Base/Resource/Robot/KUKA/KR360':
    OK.
Press [ENTER] to continue: ↵
Pattern: '*/Robot/*':
  Check '':
    Not matching.
  Check 'Base':
    Not matching.
  Check 'Base/Resource':
    Not matching.
  Check 'Base/Resource/Robot':
    Not matching.
  Check 'Base/Resource/Robot/KUKA':
    OK.
  Check 'Base/Resource/Robot/KUKA/KR360':
    OK.
Press [ENTER] to continue: ↵
Press [ENTER] to finish: ↵

Conclusion

:-) It does exactly what I expected.

Files

Text File patternSpec.cc...C++ source code
MS Visual C++ 2008 Project File patternSpec.vcproj...MS Visual C++ 2008 project file

dirk/C++/glibmm/patternSpec


Last modified: Sun Feb 28 13:52:07 2010