2010-09-25 8 views
5

Los buenos mañanaUna manera de utilizar expresiones regulares para encontrar un conjunto de nombres de fichero caminos en una cadena

¿Hay una buena manera de utilizar expresiones regulares en C# con el fin de encontrar todos los nombres de archivo y sus caminos dentro de una variable string?

Por ejemplo, si usted tiene esta cadena:

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

el resultado sería:

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

Editado: Teniendo en cuenta lo que dijo @Jim, he editado la cadena de la adición de etiquetas de para facilitar la extracción de los nombres de archivo necesarios de la cadena!

+0

¿Cuáles son sus resultados hasta ahora? –

+0

¿Deben existir archivos localmente o solo rutas de archivos bien formadas? – abatishchev

+0

¿Cómo diferenciaría entre un archivo llamado ** file20101130.csv ** y un archivo llamado ** file20101130.csv, C **? Tanto el espacio en blanco como las comas están permitidos en las extensiones de nombre de archivo, por lo tanto, no hay suerte en eso. Tendrás que encontrar algunas restricciones en los nombres de archivos para que funcionen, es decirno permitir espacios, limitar la longitud de las extensiones, etc. –

Respuesta

4

Aquí hay algo que se me ocurrió:

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

} 

Produce: (ver en 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' 

La expresión regular no es extremadamente robusto (sí hace algunas suposiciones) pero funcionó para tus ejemplos también


Aquí está una versión del programa si se utiliza <file> etiquetas. Cambiar la expresión regular y Extract a:

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

También disponible en ideone.

+0

Su código realmente está funcionando aquí. También lo he probado, agregando espacio en blanco adicional en el "archivo 20101130.csv". ¡Gracias, Aillyn! –

+0

@Aillyn: No trata el comentario de Jim Brissom (ver comentarios en op). Tampoco tiene en cuenta que las rutas pueden ser más profundas que un solo directorio y que las extensiones de archivo pueden contener espacios. – AxelEckenberger

+0

@Junior He agregado una versión de la expresión regular que usa las etiquetas ''. – Aillyn

4

Si se pone algunas restricciones en sus requisitos de nombre de archivo, puede utilizar código similar al siguiente:

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

En este caso, he limitado extensiones a una longitud de 1-5 caracteres. Obviamente, puede usar otro valor o restringir aún más los caracteres permitidos en las extensiones de nombre de archivo. La lista de caracteres válidos está tomada del artículo Naming Files, Paths, and Namespaces de MSDN.

+0

¡Buena respuesta también Jim! ¡Gracias! –

-1

Si utiliza <file> etiqueta y el texto final se podría representar documento XML como un formato correcto (en cuanto a ser xml interior, es decir texto sin etiquetas de raíz), es probable que pueda hacer:

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

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

o

var doc = new XmlDocument(); 

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

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

Ambos métodos funcionan realmente y están muy orientados a objetos, especialmente el segundo.

Y traerá bastante más rendimiento.

Véase también - Don't parse (X)HTML using RegEx

+0

-1 Desperdicio de recursos. – Aillyn

+0

@Aillyn: No, NO lo es. Analizar XML bien formado con RegEx - es mucho, mucho peor – abatishchev

+0

Ocurre que el OP está utilizando un subconjunto de XML (si se llama así) que * es * regular, por lo tanto, * puede * analizarse con RegEx. No hay absolutamente ninguna necesidad de un analizador XML. – Aillyn

Cuestiones relacionadas