2010-09-25 6 views
5

dobrzy ranoSposób, aby użyć wyrażenia regularnego do znalezienia zestawu nazw plików ścieżek w ciąg

Czy jest to dobry sposób, aby użyć wyrażenia regularnego w języku C#, aby wybrać wszystkie nazwy plików i ich ścieżki w zmiennej string?

Na przykład, jeśli masz ten ciąg:

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"; 

Wynik byłby:

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

edycja: Biorąc pod uwagę to, co powiedział @Jim, ja edytowany ciąg dodawanie znaczników w aby łatwiej wyodrębnić potrzebne nazwy plików ze stringów!

+0

Jakie są Twoje dotychczasowe wyniki? –

+0

Czy pliki istnieją lokalnie, czy też są dobrze uformowanymi ścieżkami plików? – abatishchev

+0

Jak można odróżnić plik o nazwie ** file20101130.csv ** i plik o nazwie ** file20101130.csv, C **? Zarówno spacje, jak i przecinki są dozwolone w rozszerzeniach nazw plików, więc nie ma szczęścia - musisz wymyślić pewne ograniczenia dotyczące nazw plików, aby to działało, tj.nie zezwalaj na spacje, ogranicz długość rozszerzeń itp. –

Odpowiedz

4

Oto coś wymyśliłem:

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); 
     } 
    } 

} 

Produkuje: (patrz na 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' 

regex nie jest bardzo wytrzymała (to robi kilka założeń), ale pracował dla także twoje przykłady.


Oto wersja programu, jeśli używasz znaczników <file>. Zmienić regex i Extract do:

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]); 
    } 
} 

również dostępny na ideone.

+0

Twój kod działa tutaj. Też przetestowałem, dodając dodatkowe spacje w "pliku 20101130.csv". Dziękuję Aillyn! –

+0

@Allyn: Nie zajmuje się komentarzem Jima Brissoma (patrz komentarze do op). Nie bierze również pod uwagę, że ścieżki mogą być głębsze niż tylko jeden katalog i że rozszerzenia plików mogą zawierać spacje. – AxelEckenberger

+0

@Junior Dodałem wersję regex, która używa znaczników ''. – Aillyn

4

Jeśli wstawisz kilka ograniczeń dotyczących wymagań pliku, można użyć kodu podobnego do tego:

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); 
} 

W tym przypadku, mam ograniczone rozszerzeń o długości 1-5 znaków. Możesz oczywiście użyć innej wartości lub ograniczyć dalsze dozwolone znaki w rozszerzeniach plików. Lista ważnych znaków pochodzi z artykułu MSDN Naming Files, Paths, and Namespaces.

+0

Dobra odpowiedź też Jim! Dziękuję Ci! –

-1

Jeśli używasz <file> tag a ostateczny tekst może być reprezentowana jako dobrze sformatowany dokument xml (o ile jako wewnętrznej XML, czyli tekst bez znaczników root), prawdopodobnie można zrobić:

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

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

lub

var doc = new XmlDocument(); 

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

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

Obie metody naprawdę działają i są wysoce obiektowe, zwłaszcza drugie.

I przyniesie raczej więcej wydajności.

Zobacz także - Don't parse (X)HTML using RegEx

+0

-1 Odpady zasobów. – Aillyn

+0

@Allyn: Nie, NIE jest. Parsowanie dobrze sformułowanego XML z RegEx - jest znacznie gorsze – abatishchev

+0

Zdarza się, że OP używa podzbioru XML (jeśli tak to nazywasz), że * jest * regularny, więc * może * być analizowany przy pomocy RegEx. Nie ma absolutnie potrzeby korzystania z parsera XML. – Aillyn

Powiązane problemy