LINQ:文字列中における特定文字の出現回数をカウントするには?[C#、VB].NET TIPS

LINQを使って、文字列における特定文字の出現回数をカウントする方法を解説する。LINQを使うと、何をしたいのかを簡潔に記述できる。

» 2014年11月25日 17時42分 公開
[山本康彦BluewaterSoft/Microsoft MVP for Windows Platform Development]
.NET TIPS
Insider.NET

 

「.NET TIPS」のインデックス

連載目次

対象:.NET 3.5以降


 指定された文字列中に、特定の文字が何回出現するかをカウントしたい場合、LINQを使って明瞭かつ簡潔に記述できる。本稿ではその方法を説明する。

LINQを使わない方法

 以前の.NET TIPSで紹介したように、Stringクラス(System名前空間)のReplaceメソッドとLengthプロパティを組み合わせて、次のコードのように記述できる。

using System;

class Program 
{
  // 文字の出現回数をカウント
  public static int CountChar(string s, char c) 
  {
    return s.Length - s.Replace(c.ToString(), "").Length;
  }

  static void Main() 
  {
    string s = "この文字列の中の「の」の数は?";
    Console.WriteLine(CountChar(s, 'の')); // 出力:5
#if DEBUG
    Console.ReadKey();
#endif
  }
}

Module Module1

  ' 文字の出現回数をカウント
  Public Function CountChar(ByVal s As String, ByVal c As Char) As Integer
    Return s.Length - s.Replace(c.ToString(), "").Length
  End Function

  Sub Main()
    Dim s As String = "この文字列の中の「の」の数は?"
    Console.WriteLine(CountChar(s, CChar("の"))) ' 出力:5
#If DEBUG Then
    Console.ReadKey()
#End If
  End Sub
End Module

LINQを使わずに特定文字の出現回数をカウントするコード例(上:C#、下:VB)
詳しくは「.NET TIPS 文字列中における特定文字の出現回数をカウントするには?[C#、VB]」を参照。
Visual Studioからデバッグ実行をしたとき、コンソールがすぐに閉じてしまわないように「Console.ReadKey()」と記述してある。そこで何かキーを押すとプログラムは終了する。
なお、VBのコード中でCChar関数を使用しているが、Option StrictチェックをOffにしている場合は使わなくてもよい。

 StringクラスのReplaceメソッドもLengthプロパティも効率よく動作するので、このコードで性能上は申し分ない。しかし、ReplaceメソッドとLengthプロパティを組み合わせたコードは、何をしているのか把握しづらい。そこで、この例ではメソッドに切り出し、「CountChar」というメソッド名を付けることで、コードの意図を明確にしている。

LINQを使う方法

 Stringクラスは、IEnumerable<char>/IEnumerable(Of Char)インターフェースを実装している(.NET Framework 3.5から)。従って、文字列から1文字ずつ取り出して行う処理には、System.Linq名前空間のEnumerableクラスにある拡張メソッドが利用できる。

 特定文字の出現回数をカウントするには、EnumerableクラスのWhere拡張メソッドを使って特定の文字だけを取り出し*1、その数をEnumerableクラスのCount拡張メソッドを使ってカウントすればよい(次のコード)。

using System;
using System.Linq;

class Program
{
  static void Main(string[] args)
  {
    string s = "この文字列の中の「の」の数は?";
    Console.WriteLine(s.Where(c => c == >'の').Count()); // 出力:5
#if DEBUG
    Console.ReadKey();
#endif
  }
}

Module Module1
  Sub Main()
    Dim s As String = "この文字列の中の「の」の数は?"
    Console.WriteLine(s.Where(Function(c) c = "の").Count()) ' 出力:5
#If DEBUG Then
    Console.ReadKey()
#End If
  End Sub
End Module

LINQを使って特定文字の出現回数をカウントするコード例1(上:C#、下:VB)
コードをその意図を示す名前を付けた別メソッドに切り出さずに、Mainメソッドの中に直接記述しても、Where拡張メソッドで特定の文字を取り出し、その数をCount拡張メソッドでカウントするという意図は明白である。

 LINQを使った場合は、コードの意図が明確になる。この例のように、メソッドに切り出さず、コードの流れの中に記述してしまっても問題ないだろう。

 なお、Count拡張メソッドには、カウントすべき対象をラムダ式で指定できるオーバーライドもある。それを使えば、さらに簡潔に記述できる(次のコード)。

// Console.WriteLine(s.Where(c => c == 'の').Count());
// 上の行は次のように書いてもよい
Console.WriteLine(s.Count(c => c == 'の'));

' Console.WriteLine(s.Where(Function(c) c = "の").Count())
' 上の行は次のように書いてもよい
Console.WriteLine(s.Count(Function(c) c = "の"))

LINQを使って特定文字の出現回数をカウントするコード例2(上:C#、下:VB)
Count拡張メソッドの引数に、カウントすべき対象を判別するためのラムダ式を与えてもよい。同じ結果が得られる。

 以上のように、LINQを使うと特定文字の出現回数をカウントするコードが明瞭かつ簡潔に記述できる。ただし、StringクラスのReplaceメソッドを利用した処理の方が数倍ほど速いので、カウントする処理を繰り返す場合には注意してほしい。

*1 Where拡張メソッド/Count拡張メソッドの引数には、ラムダ式を与えている。ラムダ式について詳しくは、次のMSDNのドキュメントを参照していただきたい。
  ・MSDN:ラムダ式 (C# プログラミング ガイド)
  ・MSDN:ラムダ式(Visual Basic)


利用可能バージョン:.NET Framework 3.5以降
カテゴリ:クラスライブラリ 処理対象:LINQ
使用ライブラリ:Enumerableクラス(System.Linq名前空間)
関連TIPS:LINQ:数値コレクション内の特定の数値だけを集計するには?[C#、VB]


「.NET TIPS」のインデックス

.NET TIPS

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。