RSS

Advent LINQ (6): Match

06 12月

Regexクラスを使うと正規表現を使って文字列のキャプチャが出来る。多少なりとも簡単に連続判定できるようにしてみる。

public static class LinqExtensions
{
	public static IEnumerable<Match> Match(
		this IEnumerable<string> sentences,
		string pattern,
		RegexOptions options = RegexOptions.Compiled | RegexOptions.Multiline)
	{
		var regex = new Regex(pattern, options);
		foreach (var sentence in sentences)
		{
			foreach (Match match in regex.Matches(sentence))
			{
				yield return match;
			}
		}
	}
}

これで、引数に正規表現パターンを指定するだけで、連続する文字列に処理が可能となった。

// 文字列中に存在するIPv4アドレスを抽出する
var sampleDatas[] = new[] { "IP:133.0.0.0", "IP:133.255.255.255 primary", "[192.50.0.0]", "IP\n192.50.255.255\n" };
foreach (var match in
	sampleDatas.Match(@"(?<1>\d+)(?:\.(?<1>\d+)){3}"))
{
	Console.WriteLine(match);
}

上記の例では、ハードコードされた文字列を扱っているが、Advent LINQ (2)で示したTextReader.AsEnumerableと組み合わせれば、LINQクエリ一文でファイルからの正規表現検索が実現する。壮大な時計仕掛けをやってみよう。

// 指定されたフォルダ配下のテキストファイル群からIPv4アドレスを抽出する(並列実行)
foreach (var match in
	from path in Extensions.FilesAsEnumerable(@"C:\project", "*.txt").AsParallel()
	from match in File.OpenText(path).AsEnumerable().Match(@"(?<1>\d+)(?:\.(?<1>\d+)){3}")
	select match)
{
	Console.WriteLine(match);
}

MatchはIEnumerable<string>を受け取るようになっているので、列挙子ではなく単一の文字列を受けるには、1要素の配列を作る必要がある。この部分が分かりにくいのであれば、Match(this string sentence, …) のような、単一の文字列だけを受け取るようなメソッドに変更し、明示的にselect句で射影するようにしてもよい。ただ、その場合は、正規表現をコンパイルするメリットが失われるかもしれない。

参考: .NET Frameworkがサポートする正規表現クラスを徹底活用する

広告
 
コメントする

投稿者: : 2013/12/06 投稿先 .NET, LINQ

 

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google フォト

Google アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中

 
%d人のブロガーが「いいね」をつけました。