C# 如何使用LINQ和字符串解析完成此示例?

C# 如何使用LINQ和字符串解析完成此示例?,c#,regex,linq,parsing,linq-to-objects,C#,Regex,Linq,Parsing,Linq To Objects,我正在尝试编写一个简单的程序来比较不同文件夹中的文件。我目前正在使用LINQ to对象解析文件夹,并希望在结果集中包含从字符串提取的信息 以下是我目前掌握的情况: FileInfo[] fileList = new DirectoryInfo(@"G:\Norton Backups").GetFiles(); var results = from file in fileList orderby file.CreationTime sel

我正在尝试编写一个简单的程序来比较不同文件夹中的文件。我目前正在使用LINQ to对象解析文件夹,并希望在结果集中包含从字符串提取的信息

以下是我目前掌握的情况:

FileInfo[] fileList = new DirectoryInfo(@"G:\Norton Backups").GetFiles();

var results = from file in fileList
              orderby file.CreationTime
              select new { file.Name, file.CreationTime, file.Length };

foreach (var x in results)
    Console.WriteLine(x.Name);
这将产生:

AWS025.sv2i
AWS025_C_Drive038.v2i
AWS025_C_Drive038_i001.iv2i
AWS025_C_Drive038_i002.iv2i
AWS025_C_Drive038_i003.iv2i
AWS025_C_Drive038_i004.iv2i
AWS025_C_Drive038_i005.iv2i    
...
我想修改LINQ查询,以便:

  • 它只包括实际的“备份”文件(您可以通过上面示例中的
    \u C_Drive038
    来判断备份文件,但
    038
    可能会更改驱动器号)
  • 如果文件是“主”备份文件(即,文件名末尾没有
    \u i0XX
    ),我希望包含一个字段
  • 我想包括文件的“图像编号”(例如,在本例中为
    038
  • 如果增量编号是基础文件的增量编号,则我希望包含该增量编号(例如,
    001
    将是增量编号)
我相信查询的基本布局如下所示,但我不确定如何最好地完成它(我对如何完成其中一些工作有一些想法,但我很想听听其他人可能会怎么做):

在查找
ImageNumber
IncrementNumber
时,我想假设此数据的位置并不总是固定的,这意味着,我想知道一种解析此数据的好方法(如果这需要正则表达式,请解释如何使用它)


注意:我过去解析文本的大部分经验都涉及到使用基于位置的字符串函数,例如
LEFT
RIGHT
MID
。如果有更好的方法,我不想求助于这些方法。

使用正则表达式:

    Regex regex = new Regex(@"^.*(?<Backup>_\w_Drive(?<ImageNumber>\d+)(?<Increment>_i(?<IncrementNumber>\d+))?)\.[^.]+$");
    var results = from file in fileList
                  let match = regex.Match(file.Name)
                  let IsMainBackup = !match.Groups["Increment"].Success
                  let ImageNumber = match.Groups["ImageNumber"].Value
                  let IncrementNumber = match.Groups["IncrementNumber"].Value
                  where match.Groups["Backup"].Success
                  orderby file.CreationTime
                  select new { file.Name, file.CreationTime, file.Length,
                               IsMainBackup, ImageNumber, IncrementNumber };

为这个问题找到一个好答案真是有点有趣:)

下面的代码提供了您所需要的。请注意检索文件时使用的搜索模式-检索的文件数没有必要过多。还要注意parseNumber()函数的使用,这只是为了向您展示如何将正则表达式中的字符串结果更改为需要的数字格式

static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        //Application.Run(new Form1());

        GetBackupFiles(@"c:\temp\backup files");
    }

    static void GetBackupFiles(string path)
    {
        FileInfo[] fileList = new DirectoryInfo(path).GetFiles("*_Drive*.*v2i");

        var results = from file in fileList
                      orderby file.CreationTime
                      select new 
                      {  file.Name
                        ,file.CreationTime
                        ,file.Length 
                        ,IsMainBackup = file.Extension.ToLower() == ".v2i"
                        ,ImageNumber = Regex.Match(file.Name, @"drive([\d]{0,5})", RegexOptions.IgnoreCase).Groups[1]
                        ,IncrementNumber = parseNumber( Regex.Match(file.Name, @"_i([\d]{0,5})\.iv2i", RegexOptions.IgnoreCase).Groups[1])
                      };

        foreach (var x in results)
            Console.WriteLine(x.Name);
    }

    static int? parseNumber(object num)
    {
        int temp;
        if (num != null && int.TryParse(num.ToString(), out temp))
            return temp;
        return null;
    }
}

请注意,对于regex,我假设文件名有一定的一致性,如果它们与您提到的格式不同,那么您必须对它们进行调整。

+1用于将部分工作移到GetFiles函数中,这意味着您的regex可以更简单。但是我认为你不必要地过分简化了你的正则表达式,这意味着如果有人备份了其中一个备份文件,你可能会得到错误的匹配(不是你应该这样做,但我想这可能会发生)。是的,我同意,如果名称有任何变化的可能性,正则表达式必须更加工业化。我个人更喜欢解析文件头的信息,而不是依赖文件名,但希望OP有足够的信息来开始你和我给他的信息。你们都提供了难以置信的详细答案。非常感谢!我将不得不等到下周回到工作岗位再详细复习,但这是一个极好的开始!你的回答很有帮助。两个问题:1)当你说文字反斜杠时,你是指文字下划线吗?2) 为什么不在正则表达式结尾处逃逸
\
[^.]
的句点?这很重要吗?是的,对不起,我会解决的。2) 在方括号内,句号没有特殊含义。你可以反斜杠,只是想确定一下,但这完全没有必要。你的回答非常有助于我开始理解正则表达式。我花了一段时间才把它解释清楚,但你们不同的解释部分确实起到了帮助。非常感谢。
^                   Start of string.
.*                  Allow anything at the start.
(?<Backup>...)      Match a backup description (explained below).
\.                  Match a literal period.
[^.]+$              Match the extension (anything except periods).
$                   End of string.
_\w_Drive           A literal underscore, any letter, another underscore, then the string "Drive".
(?<ImageNumber>\d+) At least one digit, saved as ImageNumber.
(?<Increment>...)?  An optional increment description.
_i                      A literal underscore, then the letter i.
(?<IncrementNumber>\d+) At least one digit, saved as IncrementNumber.
using System;
using System.IO;
using System.Text.RegularExpressions;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        FileInfo[] fileList = new FileInfo[] {
            new FileInfo("AWS025.sv2i"),
            new FileInfo("AWS025_C_Drive038.v2i"),
            new FileInfo("AWS025_C_Drive038_i001.iv2i"),
            new FileInfo("AWS025_C_Drive038_i002.iv2i"),
            new FileInfo("AWS025_C_Drive038_i003.iv2i"),
            new FileInfo("AWS025_C_Drive038_i004.iv2i"),
            new FileInfo("AWS025_C_Drive038_i005.iv2i")
        };

        Regex regex = new Regex(@"^.*(?<Backup>_\w_Drive(?<ImageNumber>\d+)(?<Increment>_i(?<IncrementNumber>\d+))?)\.[^.]+$");
        var results = from file in fileList
                      let match = regex.Match(file.Name)
                      let IsMainBackup = !match.Groups["Increment"].Success
                      let ImageNumber = match.Groups["ImageNumber"].Value
                      let IncrementNumber = match.Groups["IncrementNumber"].Value
                      where match.Groups["Backup"].Success
                      orderby file.CreationTime
                      select new { file.Name, file.CreationTime,
                                   IsMainBackup, ImageNumber, IncrementNumber };

        foreach (var x in results)
        {
            Console.WriteLine("Name: {0}, Main: {1}, Image: {2}, Increment: {3}",
                x.Name, x.IsMainBackup, x.ImageNumber, x.IncrementNumber);
        }
    }
}
Name: AWS025_C_Drive038.v2i, Main: True, Image: 038, Increment:
Name: AWS025_C_Drive038_i001.iv2i, Main: False, Image: 038, Increment: 001
Name: AWS025_C_Drive038_i002.iv2i, Main: False, Image: 038, Increment: 002
Name: AWS025_C_Drive038_i003.iv2i, Main: False, Image: 038, Increment: 003
Name: AWS025_C_Drive038_i004.iv2i, Main: False, Image: 038, Increment: 004
Name: AWS025_C_Drive038_i005.iv2i, Main: False, Image: 038, Increment: 005
static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        //Application.Run(new Form1());

        GetBackupFiles(@"c:\temp\backup files");
    }

    static void GetBackupFiles(string path)
    {
        FileInfo[] fileList = new DirectoryInfo(path).GetFiles("*_Drive*.*v2i");

        var results = from file in fileList
                      orderby file.CreationTime
                      select new 
                      {  file.Name
                        ,file.CreationTime
                        ,file.Length 
                        ,IsMainBackup = file.Extension.ToLower() == ".v2i"
                        ,ImageNumber = Regex.Match(file.Name, @"drive([\d]{0,5})", RegexOptions.IgnoreCase).Groups[1]
                        ,IncrementNumber = parseNumber( Regex.Match(file.Name, @"_i([\d]{0,5})\.iv2i", RegexOptions.IgnoreCase).Groups[1])
                      };

        foreach (var x in results)
            Console.WriteLine(x.Name);
    }

    static int? parseNumber(object num)
    {
        int temp;
        if (num != null && int.TryParse(num.ToString(), out temp))
            return temp;
        return null;
    }
}