AsfK
AsfK

Reputation: 3476

Check String contain all elements in list using Linq and case insensitive

I want to write a function that filter files in directory. The method received path, list of tokens the file must be contain and list of token that should not be in the file.

my code is like this:

private String[] enumerateFilesByFilter(String path, List<String> contain, List<String> notContain)
{
    String[] files = Directory.GetFiles(path).Where(f => (contain.All(f.Contains)) && (!notContain.Any(f.Contains))).ToArray();
    //String[] files = Directory.GetFiles(path).Where(f => f.IndexOf(contain.All(f.Contains), 0, StringComparison.CurrentCultureIgnoreCase) != -1).ToArray();
    return files;
}

I try to receive list of files that match the criteria and I succeed to obtain correct list but just for sensitive tokens.

(In the commend you can see my try to get one for case insensitive but there is an error...)

How can I check if the filename contain all string in the list in case insensitive ?

Edit

Here's an example. Let's say I have the follow files in my directory:

proj_debug_3.2.0.txt

proj_release_3.2.1.txt

proj_release_3.2.1_useThis_TRY.txt

proj_release_3.2.1_UseThis.txt

so call to

enumerateFilesByFilter(path, new List<String> { "Release", "useThis" }, new List<String> {"try", "debug" });

should return proj_release_3.2.1_UseThis.txt file

Upvotes: 0

Views: 1002

Answers (3)

AsfK
AsfK

Reputation: 3476

Finally I found solution (the solution is ugly but working):

private String[] enumerateFilesByFilter(String path, List<String> contain, List<String> notContain)
{
    String[] files = Directory.EnumerateFiles(path).Where(f => (contain.All(c => f.ToLower().Contains(c.ToLower()))) &&
        (!notContain.Any(c => f.ToLower().Contains(c.ToLower())) )).ToArray();
    return files;
}

Upvotes: 0

Gergely Hamos
Gergely Hamos

Reputation: 411

At first, I'd define a new extension method for case-insensitive search:

public static class StringExtensions
{
    public static bool Contains(this string source, string pattern, StringComparison comparision)
    {
        return source.IndexOf(pattern, comparision) >= 0;
    }
}

Then rewrite your method like this:

public static IEnumerable<string> EnumerateFilesByFilter(String path, List<String> include, List<String> exclude)
    {
        return Directory.EnumerateFiles(path).
            Where(f => include.All(i => f.Contains(i, StringComparison.OrdinalIgnoreCase))).
            Where(f => exclude.All(i => !f.Contains(i, StringComparison.OrdinalIgnoreCase)));
    }

Please note, that I used IEnumerable as return type and Directory.EnumerateFiles() for the file system listing. This way the whole operation is much more efficient, and using only enumerables.

Upvotes: 1

Tim Schmelter
Tim Schmelter

Reputation: 460108

This should work as desired:

private String[] enumerateFilesByFilter(String path, List<String> contain, List<String> notContain)
{
    String[] files = Directory.EnumerateFiles(path)
        .Where(f => contain.All(s => s.IndexOf(f, StringComparison.CurrentCultureIgnoreCase) >= 0)
             && !notContain.Any(s => s.IndexOf(f, StringComparison.CurrentCultureIgnoreCase) >= 0))
        .ToArray();
    return files;
}

Note that i use Directory.EnumerateFiles instead of Directory.GetFiles because it can start processing before all files are returned as opposed to GetFiles which first creates an array of all files.

Maybe you should also consider to use System.IO.Path.GetFileName(f) to check only the file-name instead of the full path.

Upvotes: 1

Related Questions