0

次の関数 (これは完全に機能します) では、一致が見つかった場所だけでなく、一致が何であったか... コードを返すという課題が提示されました。

txtFilePattern は、パイプで区切られたファイル拡張子のリストです。txtKeywords は、探しているキーワードの複数行のテキスト ボックスです。txtPatterns は txtKeywords と同じですが、正規表現パターン用です。

これは、C# Grep に対する私自身のちょっとした実験です。

private List<Tuple<String, Int32, String>> ScanDocuments2()
    {
        Regex searchPattern = new Regex(@"$(?<=\.(" + txtFilePattern.Text + "))", RegexOptions.IgnoreCase);
        string[] keywordtext = txtKeywords.Lines;
        List<string> keywords = new List<string>();
        List<Regex> patterns = new List<Regex>();
        for (int i = 0; i < keywordtext.Length; i++)
        {
            if (keywordtext[i].Length > 0)
            {
                keywords.Add(keywordtext[i]);
            }
        }
        string[] patterntext = txtPatterns.Lines;
        for (int j = 0; j < patterntext.Length; j++)
        {
            if (patterntext[j].Length > 0)
            {
                patterns.Add(new Regex(patterntext[j]));
            }
        }
        try
        {
            var files = Directory.EnumerateFiles(txtSelectedDirectory.Text, "*.*", SearchOption.AllDirectories).Where(f => searchPattern.IsMatch(f));
            //fileCount = files.Count();
            var lines = files.Aggregate(
                   new List<Tuple<String, Int32, String>>(),
                   (accumulator, file) =>
                   {
                       fileCount++;
                       using (var reader = new StreamReader(file))
                       {
                           var counter = 0;
                           String line;
                           while ((line = reader.ReadLine()) != null)
                           {
                               if (keywords.Any(keyword => line.ToLower().Contains(keyword.ToLower())) || patterns.Any(pattern => pattern.IsMatch(line)))
                               {
                                   //cleans up the file path for grid
                                   string tmpfile = file.Replace(txtSelectedDirectory.Text, "..");
                                   accumulator.Add(Tuple.Create(tmpfile, counter, line));
                               }
                               counter++;
                           }
                       }
                       return accumulator;
                   },
                   accumulator => accumulator
            );
            return lines;
        }
        catch (UnauthorizedAccessException UAEx)
        {
            Console.WriteLine(UAEx.Message);
            throw UAEx;
        }
        catch (PathTooLongException PathEx)
        {
            Console.WriteLine(PathEx.Message);
            throw PathEx;
        }
    }

問題は、どのキーワードまたはパターンが返されるタプルに一致したかを判断するにはどうすればよいかということです。

4

2 に答える 2

1

一致するパターンを保持するために新しい変数を導入し、FirstOrDefault代わりにAny. 次に、新しい変数が一致しない限り、null一致したパターンがあり、タプル内でそれを返すことができます。

例えば

...
        new List<Tuple<String, Int32, String, Regex>>()
...
                       while ((line = reader.ReadLine()) != null)
                       {
                           Regex matchingReg = patterns.FirstOrDefault(pattern => pattern.IsMatch(line));

                           if (keywords.Any(keyword => line.ToLower().Contains(keyword.ToLower())) || matchingReg != null)
                           {
                               //cleans up the file path for grid
                               string tmpfile = file.Replace(txtSelectedDirectory.Text, "..");
                               accumulator.Add(Tuple.Create(tmpfile, counter, line, matchingReg));
                           }
                           counter++;
                       }
...
于 2013-02-27T18:22:34.090 に答える
1

リファクタリングされたコードを次に示します。ケネスの考えは正しかった。

private IEnumerable<LineMatch> ScanDocuments2()
{
    string[] keywordtext = txtKeywords.Lines;
    string[] patterntext = txtPatterns.Lines;

    Regex searchPattern = GetSearchPattern();
    var keywords = GetKeywords(keywordtext).ToList();
    var patterns = GetPatterns(patterntext).ToList();

    try
    {
        var files = GetFiles(searchPattern);

        var lines = files.Aggregate(
               new List<LineMatch>(),
               (accumulator, file) =>
               {

                foreach(var item in EnumerateFile(file, keywords, patterns))
                {
                  accumulator.Add(item);
                }

                   return accumulator;
               },
               accumulator => accumulator
        );
        return lines;
    }
    catch (UnauthorizedAccessException UAEx)
    {
        Console.WriteLine(UAEx.Message);
        throw;
    }
    catch (PathTooLongException PathEx)
    {
        Console.WriteLine(PathEx.Message);
        throw;
    }
}

private LineMatch EnumerateFile(string file, IEnumerable<string> keywords, IEnumerable<Regex> patterns)
{
  var counter = 0;

  foreach(var line in File.ReadLines(file))
  {
    var matchingRegex = patterns.FirstOrDefault(p => p.IsMatch(line));
    var keyword = keywords.FirstOrDefault(k => line.ToLower().Contains(k.ToLower()));

    if(keyword == null && matchingRegex == null) continue;

    string tmpfile = file.Replace(txtSelectedDirectory.Text, "..");

    yield return new LineMatch
    {
        Counter = counter,
        File = tmpfile,
        Line = line,
        Pattern = matchingRegex == null ? null : matchingRegex.Pattern,
        Keyword = keyword
    };

    counter++;
  }
}

private IEnumerable<string> GetFiles(Regex searchPattern)
{
  return Directory.EnumerateFiles(txtSelectedDirectory.Text, "*.*", SearchOption.AllDirectories).Where(f => searchPattern.IsMatch(f));
}

private IEnumerable<string> GetKeywords(IEnumerable<string> keywordtext)
{
  foreach(var keyword in keywordtext)
  {
    if(keyword.Length <= 0) continue;

    yield return keyword;
  }
}

private IEnumerable<string> GetPatterns(IEnumerable<string> patterntext)
{
  foreach(var pattern in patterntext)
  {
    if(pattern.Length <= 0) continue;

    yield return new Regex(pattern);
  }
}

private Regex GetSearchPattern()
{
  return new Regex(string.Format(@"$(?<=\.({0}))",  txtFilePattern.Text), RegexOptions.IgnoreCase);
}

public class LineMatch
{
  public int Counter { get; set; }
  public string File { get; set; }
  public string Line { get; set; }
  public string Pattern { get; set; }
  public string Keyword { get; set; }
}
于 2013-02-27T20:33:14.290 に答える