web-dev-qa-db-fra.com

Comment filtrer une liste de chaînes correspondant à un modèle

J'ai une liste de chaînes (noms de fichiers en fait) et je voudrais garder uniquement celles qui correspondent à une expression de filtre comme: \*_Test.txt.

Quel serait le meilleur pour y parvenir?

Voici la réponse que j'ai trouvée:

List<string> files = new List<string>();
files.Add("MyFile1.csv");
files.Add("MyFile1_Test.txt");
files.Add("MyFile2.csv");
files.Add("MyFile2_Test.txt");
files.Add("MyFile3.csv");
files.Add("MyFile3_Test.txt");
files.Add("MyFile_Testtxttxt.txt");

// Define a filter
string filter = "*_Test.txt";

// Make the filter regex safe
foreach (char x in @"\+?|{[()^$.#")
    filter = filter.Replace(x.ToString(), @"\" + x.ToString());

filter = string.Format("^{0}$",filter.Replace("*", ".*"));

// Old School
List<string> resultList1 = files.FindAll(delegate(string s) { return Regex.IsMatch(s, filter, RegexOptions.IgnoreCase); });

// Version using LINQ
List<string> resultList2 = files.Where(x =>  Regex.IsMatch(x, filter, RegexOptions.IgnoreCase) == true ).ToList();
19
TeamWild

Vous voudrez probablement utiliser une expression régulière pour cela si vos modèles vont être complexes ....

vous pouvez soit utiliser une expression régulière appropriée comme filtre (par exemple, pour votre exemple spécifique, ce serait new Regex(@"^.*_Test\.txt$") ou vous pouvez appliquer un algorithme de conversion.

Dans les deux cas, vous pouvez simplement utiliser linq pour appliquer l'expression régulière.

par exemple

var myRegex=new Regex(@"^.*_Test\.txt$");
List<string> resultList=files.Where(myRegex.IsMatch).ToList();

Certaines personnes peuvent penser que la réponse ci-dessus est incorrecte, mais vous pouvez utiliser un groupe de méthodes au lieu d'un lambda. Si vous souhaitez la lamda complète, vous utiliserez:

var myRegex=new Regex(@"^.*_Test\.txt$");
List<string> resultList=files.Where(f => myRegex.IsMatch(f)).ToList();

ou non Linq

List<string> resultList=files.FindAll(delegate(string s) { return myRegex.IsMatch(s);});

si vous convertissiez le filtre, une simple conversion serait

 var myFilter="*_Test.txt";
 var myRegex=new Regex("^" + myFilter.Replace("*",".*") +"$");

Vous pouvez alors également avoir des filtres comme "*Test*.txt" avec cette méthode.

Cependant, si vous descendiez cette route de conversion, vous devez vous assurer d'avoir échappé à tous les caractères d'expressions régulières spéciales, par exemple "." devient @ ".", "(" devient @ "(" etc .......

Modifier - L'exemple de remplacement est TROP simple car il ne convertit pas le. il trouverait donc "fish_Textxtxt" alors échappez au moins au .

alors

string myFilter="*_Test.txt";
foreach(char x in @"\+?|{[()^$.#") {
  myFilter = myFilter.Replace(x.ToString(),@"\"+x.ToString());
}
Regex myRegex=new Regex(string.Format("^{0}$",myFilter.Replace("*",".*")));
30
Bob Vale

Avez-vous essayé LINQ:

List<string> resultList = files.Where(x => x.EndsWith("_Test.txt")).ToList();

ou si vous l'exécutez sur une ancienne version .NET (<3.5):

List<string> resultList = files.FindAll(delegate(string s) { 
    return s.EndsWith("_Test.txt"); 
});
8
Darin Dimitrov

Cela a fonctionné pour moi et est assez simple:

List<string> keys = new List<string>();
//populate your list
var myregex = new Regex("^.+$");
List<string> matchlist = keys.Where(i=>myregex.IsMatch(i)).ToList();
1
Chad Kuehn