2010-09-25 6 views
5

Les bons gars du matinUne façon d'utiliser RegEx pour trouver un ensemble de chemins de noms de fichiers dans une chaîne

est-il un bon moyen d'utiliser l'expression régulière en C# afin de trouver tous les fichiers et leurs chemins dans une variable string?

Par exemple, si vous avez cette chaîne:

string s = @"Hello John 

these are the files you have to send us today: <file>C:\Development\Projects 2010\Accounting\file20101130.csv</file>, <file>C:\Development\Projects 2010\Accounting\orders20101130.docx</file> 

also we would like you to send <file>C:\Development\Projects 2010\Accounting\customersupdated.xls</file> 

thank you"; 

Le résultat serait:

C:\Development\Projects 2010\Accounting\file20101130.csv 
C:\Development\Projects 2010\Accounting\orders20101130.docx 
C:\Development\Projects 2010\Accounting\customersupdated.xls 

ÉDITÉE: Considérant que dit @ Jim, j'ai modifié la chaîne dans l'ajout de balises Afin de faciliter l'extraction des noms de fichiers nécessaires à partir de la chaîne!

+0

Quels sont les résultats jusqu'à présent? –

+0

Les fichiers doivent-ils exister localement ou être des chemins de fichiers bien formés? – abatishchev

+0

Comment feriez-vous la différence entre un fichier nommé ** file20101130.csv ** et un fichier nommé ** file20101130.csv, C **? Les espaces et les virgules sont autorisés dans les extensions de noms de fichiers, donc pas de chance - vous devrez trouver des contraintes sur les noms de fichiers pour que cela fonctionne, c'est-à-direinterdire espaces, limiter la longueur des extensions –

Répondre

4

est ici quelque chose que je suis venu avec:

using System; 
using System.Text.RegularExpressions; 

public class Test 
{ 

    public static void Main() 
    { 
     string s = @"Hello John these are the files you have to send us today: 
      C:\projects\orders20101130.docx also we would like you to send 
      C:\some\file.txt, C:\someother.file and d:\some file\with spaces.ext 

      Thank you"; 

     Extract(s); 

    } 

    private static readonly Regex rx = new Regex 
     (@"[a-z]:\\(?:[^\\:]+\\)*((?:[^:\\]+)\.\w+)", RegexOptions.IgnoreCase); 

    static void Extract(string text) 
    { 
     MatchCollection matches = rx.Matches(text); 

     foreach (Match match in matches) 
     { 
      Console.WriteLine("'{0}'", match.Value); 
     } 
    } 

} 

Produit: (Voir ideone)

'C:\projects\orders20101130.docx', file: 'orders20101130.docx' 
'C:\some\file.txt', file: 'file.txt' 
'C:\someother.file', file: 'someother.file' 
'd:\some file\with spaces.ext', file: 'with spaces.ext' 

Le regex n'est pas extrêmement robuste (cela fait quelques hypothèses), mais il a travaillé pour vos exemples aussi.


Voici une version du programme si vous utilisez <file> balises. Changer l'expression rationnelle et Extract à:

private static readonly Regex rx = new Regex 
    (@"<file>(.+?)</file>", RegexOptions.IgnoreCase); 

static void Extract(string text) 
{ 
    MatchCollection matches = rx.Matches(text); 

    foreach (Match match in matches) 
    { 
     Console.WriteLine("'{0}'", match.Groups[1]); 
    } 
} 

Egalement disponible sur ideone.

+0

Votre code fonctionne vraiment ici. J'ai également testé, en ajoutant des espaces supplémentaires dans le "fichier 20101130.csv". Merci Aillyn! –

+0

@Aillyn: Ne traite pas du commentaire de Jim Brissom (voir les commentaires sur op). Il ne tient également pas compte du fait que les chemins peuvent être plus profonds qu'un seul répertoire et que les extensions de fichier peuvent contenir des espaces. – AxelEckenberger

+0

@Junior J'ai ajouté une version de la regex qui utilise les balises ''. – Aillyn

4

Si vous mettez des contraintes sur vos besoins de nom de fichier, vous pouvez utiliser un code similaire à ceci:

string s = @"Hello John 

these are the files you have to send us today: C:\Development\Projects 2010\Accounting\file20101130.csv, C:\Development\Projects 2010\Accounting\orders20101130.docx 

also we would like you to send C:\Development\Projects 2010\Accounting\customersupdated.xls 

thank you"; 

Regex regexObj = new Regex(@"\b[a-z]:\\(?:[^<>:""/\\|?*\n\r\0-\37]+\\)*[^<>:""/\\|?*\n\r\0-\37]+\.[a-z0-9\.]{1,5}", RegexOptions.IgnorePatternWhitespace|RegexOptions.IgnoreCase); 
MatchCollection fileNameMatchCollection = regexObj.Matches(s); 
foreach (Match fileNameMatch in fileNameMatchCollection) 
{ 
    MessageBox.Show(fileNameMatch.Value); 
} 

Dans ce cas, je me suis limité des extensions à une longueur de 1-5 caractères. Vous pouvez évidemment utiliser une autre valeur ou restreindre davantage les caractères autorisés dans les extensions de nom de fichier. La liste des caractères valides est extraite de l'article MSDN Naming Files, Paths, and Namespaces.

+0

Bonne réponse aussi Jim! Je vous remercie! –

-1

Si vous utilisez balise <file> et le texte final pourrait être représenté document XML ainsi formaté (dans la mesure comme étant xml intérieure, texte-à-dire sans balises racine), vous pouvez probablement faire:

var doc = new XmlDocument(); 
doc.LoadXml(String.Concat("<root>", input, "</root>")); 

var files = doc.SelectNodes("//file"): 

ou

var doc = new XmlDocument(); 

doc.AppendChild(doc.CreateElement("root")); 
doc.DocumentElement.InnerXml = input; 

var nodes = doc.SelectNodes("//file"); 

Les deux méthodes fonctionnent vraiment et sont fortement orientées objet, en particulier la seconde.

Et apportera plutôt plus de performance.

Voir aussi - Don't parse (X)HTML using RegEx

+0

-1 Déchets de ressources. – Aillyn

+0

@Aillyn: Non, ce n'est pas. Parsing XML bien formé avec RegEx - est beaucoup, beaucoup pire – abatishchev

+0

Il arrive que l'OP utilise un sous-ensemble de XML (si vous l'appelez cela) que * est * régulier, donc, il * peut * être analysé avec RegEx. Il n'y a absolument pas besoin d'un analyseur XML. – Aillyn

Questions connexes