C#を使用したアプリケーション開発において、文字列の中に特定の文字が含まれているかどうかを判定するシーンは非常に多く存在します。
標準的なstring.Containsメソッドも便利ですが、LINQのAnyメソッドを活用することで、より複雑な条件や柔軟な判定が可能になります。
本記事では、LINQのAnyを使って効率的に文字の含有判定を行う方法を、基礎から応用まで詳しく解説します。
LINQのAnyメソッドとは何か
LINQ(Language Integrated Query)のAnyメソッドは、シーケンス(配列やリストなど)の中に、指定した条件を満たす要素が一つでも存在するかどうかを判定するためのメソッドです。
戻り値はbool型で、条件に一致するものが見つかれば即座にtrueを返し、最後まで見つからなければfalseを返します。

C#においてstring型はIEnumerable<char>インターフェースを実装しているため、文字列を「文字の集合」として扱うことができます。
これにより、文字列に対して直接LINQの拡張メソッドを呼び出すことが可能になっています。
特定の文字が含まれているかを確認する際、単純な文字の一致だけでなく、「数字が含まれているか」「記号が含まれているか」といった抽象的な条件を指定できるのがAnyの強みです。
Anyメソッドの基本的な構文
Anyメソッドには、引数を持たない形式と、ラムダ式を引数に取る形式の2種類があります。
文字の判定においては、主に後者のラムダ式を用いる形式が活躍します。
| メソッド形式 | 役割 |
|---|---|
Any() | シーケンスに要素が1つでもあるかを確認する |
Any(predicate) | 条件(ラムダ式)を満たす要素が1つでもあるかを確認する |
文字が含まれているかどうかの判定では、「どの文字を探すか」という条件をラムダ式で記述することになります。
特定の文字が含まれるか判定する基本コード
まずは、最もシンプルな例として、ある文字列の中に特定の文字が含まれているかを確認するコードを見てみましょう。
using System;
using System.Linq; // LINQを使用するために必要
class Program
{
static void Main()
{
string targetText = "Hello LINQ World";
// 文字 'L' が含まれているか判定
bool hasLetterL = targetText.Any(c => c == 'L');
// 結果の出力
Console.WriteLine($"'L' は含まれているか: {hasLetterL}");
// 小文字の 'z' が含まれているか判定
bool hasLetterZ = targetText.Any(c => c == 'z');
Console.WriteLine($"'z' は含まれているか: {hasLetterZ}");
}
}
'L' は含まれているか: True
'z' は含まれているか: False
このサンプルコードでは、targetText.Any(c => c == 'L') という記述により、文字列内の各文字を c という変数に取り出し、それが 'L' と等しいかをチェックしています。
Containsメソッドとの違い
「特定の文字が含まれるか」を調べるだけであれば、string.Containsメソッドでも事足ります。
しかし、Anyを使用するメリットは条件の柔軟性にあります。
Containsは特定の値との完全一致を調べますが、Anyは「文字の種類」や「複数の条件の組み合わせ」を評価するのに適しています。
複数の文字のいずれかが含まれるか判定する方法
実務では、「特定の文字セット(例:A, B, C)のいずれかが含まれているか」を判定したい場面がよくあります。
これをAnyで実現する方法を解説します。

文字配列を用いた判定
判定したい文字をあらかじめ配列やリストにしておき、それらと照合する方法です。
using System;
using System.Linq;
class Program
{
static void Main()
{
string input = "User_Name_123";
// 判定したい特定の文字リスト
char[] specialChars = { '!', '@', '#', '$', '%' };
// 入力文字列の中に、specialCharsのいずれかが含まれているか
bool containsSpecial = input.Any(c => specialChars.Contains(c));
Console.WriteLine($"特殊記号が含まれているか: {containsSpecial}");
string input2 = "Hello! User";
bool containsSpecial2 = input2.Any(c => specialChars.Contains(c));
Console.WriteLine($"特殊記号が含まれているか: {containsSpecial2}");
}
}
特殊記号が含まれているか: False
特殊記号が含まれているか: True
このコードでは、input.Any の中でさらに specialChars.Contains(c) を呼び出しています。
これは「入力文字 c が、specialChars 配列の中に存在するか」を判定しており、「いずれかの文字が含まれるか」というロジックを簡潔に記述できています。
文字の種類(数字・記号など)で判定する
LINQのAnyが真価を発揮するのは、char構造体の静的メソッドと組み合わせたときです。
char.IsDigitやchar.IsUpperなどを使うことで、具体的な文字を指定せずに「数字が含まれているか」といった判定が可能になります。
数字が含まれているかの判定
using System;
using System.Linq;
class Program
{
static void Main()
{
string pass1 = "Password";
string pass2 = "Pass1234";
// 数字が含まれているか
bool hasDigit1 = pass1.Any(char.IsDigit);
bool hasDigit2 = pass2.Any(char.IsDigit);
Console.WriteLine($"pass1に数字はあるか: {hasDigit1}");
Console.WriteLine($"pass2に数字はあるか: {hasDigit2}");
}
}
pass1に数字はあるか: False
pass2に数字はあるか: True
Any(char.IsDigit) という記述は、Any(c => char.IsDigit(c)) の省略形(メソッド参照)です。
非常に読みやすく、直感的なコードになります。
よく使われる判定メソッド一覧
char構造体には以下のような便利なメソッドが用意されています。
これらをAnyに渡すことで、高度なバリデーションが可能です。
| メソッド名 | 判定内容 |
|---|---|
char.IsDigit | 十進数字であるか(0-9) |
char.IsLetter | 文字(アルファベットなど)であるか |
char.IsUpper | 大文字であるか |
char.IsLower | 小文字であるか |
char.IsPunctuation | 句読点や記号であるか |
char.IsWhiteSpace | 空白文字(スペース、タブ、改行)であるか |
大文字・小文字を区別せずに判定する
文字列の比較において、大文字と小文字を区別したくない場合があります。
Anyを使用する場合、ラムダ式の中で各文字を変換してから比較することで、これを実現できます。

using System;
using System.Linq;
class Program
{
static void Main()
{
string message = "Welcome to CSharp";
char target = 'w';
// 大文字小文字を区別せずに 'w' が含まれるか判定
bool exists = message.Any(c => char.ToLower(c) == char.ToLower(target));
Console.WriteLine($"'w' (大文字小文字不問) は含まれるか: {exists}");
}
}
'w' (大文字小文字不問) は含まれるか: True
このように、char.ToLower や char.ToUpper を介すことで、柔軟な比較条件をインラインで記述できます。
複雑な条件:複数の文字がすべて含まれているか
Anyは「いずれか一つ」を判定するものですが、逆に「特定の文字がすべて含まれているか」を判定したい場合は、Allメソッドや、Anyの組み合わせを使用します。
例えば、「パスワードに『英大文字』と『数字』の両方が少なくとも1つずつ含まれているか」という条件を考えます。
using System;
using System.Linq;
class Program
{
static void Main()
{
string password = "SafePassword7";
// 大文字が含まれているか 且つ 数字が含まれているか
bool isComplex = password.Any(char.IsUpper) && password.Any(char.IsDigit);
Console.WriteLine($"要件を満たしているか: {isComplex}");
}
}
要件を満たしているか: True
このように、Anyを論理演算子でつなぐことで、複合的なバリデーションも簡潔に実装できます。
パフォーマンスに関する注意点:ショートサーキット評価
LINQのAnyは、パフォーマンスの観点からも優れています。
その理由はショートサーキット(短絡評価)が行われるためです。
例えば、100万文字ある長い文字列の先頭に目的の文字があった場合、Anyは最初の1文字をチェックした時点でtrueを返し、残りの99万9999文字のチェックをスキップします。

// 概念的な動作イメージ
bool result = longString.Any(c => {
Console.WriteLine("チェック中..."); // 一致した時点でこの出力は止まる
return c == 'A';
});
この特性により、大きなデータセットに対しても効率的に動作します。
ただし、逆に「一致しない場合」は最後まで走査する必要があるため、最悪計算量はO(n)となります。
Anyを使った空文字列の判定
Any() (引数なし) を文字列に対して呼び出すと、「文字列が1文字以上あるか(空でないか)」を判定できます。
string empty = "";
string notEmpty = "Hello";
bool hasChars1 = empty.Any(); // False
bool hasChars2 = notEmpty.Any(); // True
ただし、C#では伝統的に string.IsNullOrEmpty や string.IsNullOrWhiteSpace が使われます。
LINQの Any() は null に対して呼び出すと例外を投げるため、安全性の観点からは標準的な文字列メソッドを使用するのが一般的です。
実践例:不正な文字の検知
ユーザー入力の中に、使用を禁止したい文字が含まれていないかをチェックする実用的な例を紹介します。
using System;
using System.Linq;
class Program
{
static void Main()
{
// ユーザー名に使用できない文字の定義
char[] invalidChars = { '<', '>', '/', '\\', ';', ':' };
string userName = "Admin<User>";
// 不正な文字が含まれているかチェック
bool containsInvalid = userName.Any(c => invalidChars.Contains(c));
if (containsInvalid)
{
Console.WriteLine("エラー: ユーザー名に使用できない記号が含まれています。");
}
else
{
Console.WriteLine("ユーザー名は有効です。");
}
}
}
エラー: ユーザー名に使用できない記号が含まれています。
このパターンは、Webフォームのバリデーションやファイル名のチェックなどで非常に役立ちます。
まとめ
C#のLINQ Anyメソッドは、文字列の中に特定の文字が含まれているかを判定するための非常に強力な道具です。
単一の文字だけでなく、文字の種類や複数の候補、複雑な条件を組み合わせた判定が、読みやすいコードで記述できるのが最大の魅力です。
また、条件に一致した瞬間に処理を終了するショートサーキット特性により、無駄な計算を省ける効率性も備えています。
char構造体のメソッドと組み合わせて、ぜひ日々のコーディングに活用してみてください。
より高度な文字列操作が必要な場合は、正規表現(Regex)の検討も必要ですが、シンプルな判定であればLINQ Anyの方が可読性と保守性の面で優れていることが多いでしょう。
