Как я мог бы завершить этот пример с помощью строкового парсинга и LINQ?

Я пытаюсь записать простую программу, которая сравнит файлы в отдельных папках. Я в настоящее время использую LINQ для Объектов проанализировать папку и хотел бы к включенной информации, извлеченной из строки в моем наборе результатов также.

Вот то, что я имею до сих пор:

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 так, чтобы:

  • Это только включает фактические "резервные" файлы (можно сказать файлы резервных копий из-за _C_Drive038 в примерах выше, хотя 038 и возможно буква диска могла измениться).
  • Я хочу включать поле, если файл является "основным" файлом резервной копии (т.е. это не имеет _i0XX в конце имени файла).
  • Я хочу включать "номер изображения" файла (например, в этом случае это 038).
  • Я хочу включать инкрементное число, если это - incrememnt основного файла (например. 001 было бы инкрементное число),

Я полагаю, что базовый макет запроса был бы похож на следующее, но я не уверен, как лучше всего завершить его (я получил некоторое представление для того, как часть этого могла бы быть сделана, но мне интересно к услышанному, как другие могли бы сделать это):

var results = from file in fileList
              let IsMainBackup = \\ ??
              let ImageNumber = \\ ??
              let IncrementNumber = \\ ??
              where \\ it is a backup file.
              orderby file.CreationTime
              select new { file.Name, file.CreationTime, file.Length, 
                           IsMainBackup, ImageNumber, IncrementNumber };

При поиске ImageNumber и IncrementNumber, Я хотел бы предположить, что местоположение этих данных не всегда фиксируется, значение, я хотел бы знать о хорошем способе проанализировать это (Если это требует RegEx, объясните, как я мог бы использовать его).

Примечание: Большая часть моего прошлого опыта в парсинге текста, включенного с помощью основанных на местоположении строковых функций, такой как LEFT, RIGHT, или MID. Я не возвратился бы к ним, если существует лучший путь.

5
задан Marc Gravell 23 December 2009 в 22:02
поделиться

2 ответа

Использование регулярных выражений:

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

Вот описание регулярного выражения:

^                   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
6
ответ дан 13 December 2019 в 19:28
поделиться

Было немного весело разработать хороший ответ на этот вопрос :)

Приведенный ниже фрагмент кода дает вам то, что вам нужно. Обратите внимание на использование шаблона поиска при извлечении файлов - нет смысла извлекать больше файлов, чем необходимо. Также обратите внимание на использование функции 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;
    }
}

Обратите внимание, что с регулярными выражениями я предполагаю некоторую согласованность в именах файлов, если они будут отличаться от указанного вами формата, вам придется их скорректировать.

5
ответ дан 13 December 2019 в 19:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: