-
May 7th, 2011, 06:19 PM
#1
[RESOLVED] Filtering array items according to a dynamically created predicate
I just encountered the requirement to filter array items according to a dynamically created predicate, i.e. one determined by user input. I didn't find anything really enlightening on MSDN (the sample on Array::FindAll<T> only demonstrates hard-coded predicates) or CodeGuru, so I rolled my own. It involves an extra class created for the sole purpose of representing the predicate. It goes something like this:
Code:
// Test1.cpp: Hauptprojektdatei.
#include "stdafx.h"
using namespace System;
using namespace System::IO;
using namespace System::Text::RegularExpressions;
// Regular expression predicate class
public ref class RegexPredicate
{
public:
RegexPredicate(String ^strRegex, RegexOptions opt) : m_regex(gcnew Regex(strRegex, opt))
{
m_pred = gcnew Predicate<String ^>(this, &RegexPredicate::PredFunc);
}
initonly Predicate<String ^> ^m_pred;
private:
bool PredFunc(String ^s)
{
return m_regex->IsMatch(s);
}
initonly Regex ^m_regex;
};
int main(array<System::String ^> ^args)
{
if (args->Length != 1) {
Console::WriteLine("Usage: Invoke this program with a dir-style file name match pattern as the only\n"
"command line argument");
#ifdef _DEBUG
Console::WriteLine();
Console::WriteLine("Hit enter to continue...");
Console::ReadLine();
#endif
return 1;
}
// Build an array of all file names without absolute path
array<FileInfo ^> ^afi = (gcnew DirectoryInfo("."))->GetFiles();
array<String ^> ^astrFileNames = gcnew array<String ^>(afi->Length);
for (int i = 0; i < afi->Length; ++i)
astrFileNames[i] = afi[i]->Name;
// Construct regex predicate object based on the dir-style wildcard pattern converted to a regex
RegexPredicate ^rxp =
gcnew RegexPredicate(String::Concat("^", args[0]->Replace(".", "\\.")->Replace("?", ".?")->Replace("*", ".*"), "$"),
RegexOptions::IgnoreCase);
// Filter the file names according to the predicate
array<String ^> ^astrFilteredFileNames = Array::FindAll(astrFileNames, rxp->m_pred);
// List the filtered file names
for (int i = 0; i < astrFilteredFileNames->Length; ++i)
Console::WriteLine(astrFilteredFileNames[i]);
Console::WriteLine();
Console::WriteLine("{0} out of {1} files matched the predicate", astrFilteredFileNames->Length, astrFileNames->Length);
#ifdef _DEBUG
Console::WriteLine();
Console::WriteLine("Hit enter to continue...");
Console::ReadLine();
#endif
return 0;
}
You can see, the predicate class holds the raw predicate (i.e. the delegate) and the predicate function, along with the data needed to determine the match. It works like a charm and is nicely encapsulated, however, since this certainly is something that's required in a vast lot of programs, I wonder whether there is any more straightforward and/or elegant way to achieve this.
Of course the above code is just a demo program. Even my XP already has a dir command and the classes in the System::IO namespace do a good job filtering file names as well. This is just a model of what I need to do (and am currently doing that way) in another app.
Any comments are welcome.
Last edited by Eri523; May 7th, 2011 at 11:04 PM.
Reason: Fixed a comment in the code
I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.
This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|