2014/10/11

【C#】フォルダ配下をGrepして行番号と文字列を取得する

あるプログラムでGrep結果を取得したい場合、コマンドプロンプトの「FINDSTR」やサクラエディタの「GREP」などのコマンドを使えば、Grepはできる。
しかし、その結果を戻り値として受け取ることができない。

そこで、仕方なくC#でGrepする機能を実装してみた。



フォルダ配下をGrepする


たとえば、以下のようなHTMLファイルがフォルダ配下に複数あったとする。
<!DOCTYPE html>
<html>
<head>
    <title>C#でGrep</title>
</head>
<body>
    <ul>
    <li><a href="./menu.html">メニュー</a></li>
    <li><a href="./blog.html">ブログ</a></li>
    <li><a href="./mail.html">メールフォーム</a></li>
    </ul>
</body>
</html>

それをC#でサブディレクトリも対象にしてGrepする場合は、以下のような処理になる。

using System.IO;
using System.Linq;
using System.Text;

var enc = Encoding.GetEncoding("shift_jis");

foreach (var f in Directory.GetFiles(@"C:\HtmlFolder"
                                    , "*.html"
                                    , SearchOption.AllDirectories))
{
    var grep = File.ReadAllLines(@f, enc)
                .Select((s, i) => new {Index = i, Value = s})
                .Where(s => s.Value.Contains("title") 
                            || s.Value.Contains("<a>"));

    foreach (var g in grep)
    {
        // 表示結果
        //   004:<title>C#でGrep</title>
        //   008:<li><a href="./menu.html">メニュー</a>
        Console.WriteLine("{0:000}:{1}", g.Index, g.Value);
    }
}

こんな感じでGrepすることができる。

System.IO.Directory.GetFilesで、指定したフォルダ配下のファイルを取得している。
SearchOption.AllDirectoriesを指定することでサブディレクトリまで検索できる。
SearchOption.TopDirectoryOnlyを指定すれば、サブディレクトリは含まれない。

System.IO.File.ReadAllLinesで、ファイルをstring型の配列として一気に読み込み、LINQを使って整形していく。

Select((s, i) => new {Index = i, Value = s}) は、Enumerable.Selectを使って、配列の値とインデックスを取得して、匿名型に格納している。

Where(s => s.Value.Contains(“title”))は、Selectで抽出したValueの中に「文字列("title")」が含まれるかどうか判定している。これにより「文字列("title")」が含まれる業のみが抽出される。

ここで、注意すべき点は、ReadAllLines.Where.Selectのようにしないことだ。
最初にフルイにかけちゃうと、元々のインデックスは崩れてしまい、Whereで絞りこまれたあとの配列のインデックスになってしまう。



参考



以上

written by @bc_rikko

0 件のコメント :

コメントを投稿