C#を用いたアプリケーション開発において、文字列操作は避けては通れない非常に重要な要素です。
その中でも、特定の文字列が指定したパターンから始まっているかを確認する「前方一致判定」は、データのバリデーション、ファイルパスの解析、コマンドライン引数の処理など、幅広いシーンで活用されます。
C#には標準で StartsWithメソッド が用意されており、直感的に記述できるだけでなく、オプションによって動作を細かく制御することが可能です。
本記事では、C#における前方一致判定の基本から、大文字小文字の区別といった実務的な設定、さらには最新の .NET 環境で推奨される ReadOnlySpanを用いた高速化手法 までをプロの視点で徹底解説します。
StartsWithメソッドの基本
C#で前方一致を確認する最も標準的な方法は、System.String クラスに定義されている StartsWith メソッドを使用することです。
このメソッドは、呼び出し元の文字列が引数で指定された文字列で始まる場合に true を返し、それ以外の場合に false を返します。
基本的な構文と使用例
まずは、最もシンプルな使い方を見ていきましょう。
以下のプログラムでは、URLのプロトコルが「https」で始まっているかどうかを判定しています。
using System;
public class Program
{
public static void Main()
{
string url = "https://example.com";
// 基本的な前方一致判定
if (url.StartsWith("https"))
{
Console.WriteLine("このURLはセキュアなプロトコルを使用しています。");
}
else
{
Console.WriteLine("このURLはhttpsで始まっていません。");
}
}
}
このURLはセキュアなプロトコルを使用しています。
この例のように、StartsWith は非常にシンプルに記述できます。
しかし、実務においては「大文字と小文字を区別したくない」場合や、「特定の言語文化(カルチャ)に基づいて比較したい」場合が多くあります。
大文字・小文字の区別とStringComparison
デフォルトの StartsWith(string) メソッドは、大文字と小文字を厳密に区別します。
例えば、”HTTPS” という文字列に対して “https” で判定を行うと、結果は false となります。
これを制御するためには、第2引数に StringComparison 列挙型を指定します。
StringComparisonの主な種類
実務で頻繁に利用されるのは、主に以下の3つです。
- Ordinal: バイナリ値に基づいて比較します。最も高速で、大文字小文字を区別します。
- OrdinalIgnoreCase: バイナリ値に基づいて比較しますが、大文字小文字を区別しません。
- CurrentCultureIgnoreCase: 現在の実行環境の言語設定(カルチャ)を考慮し、大文字小文字を区別せずに比較します。
実装例:大文字小文字を無視した判定
ユーザーの入力や設定ファイルの読み込みなど、表記の揺れが予想される場面では StringComparison.OrdinalIgnoreCase を使用するのが一般的です。
using System;
public class Program
{
public static void Main()
{
string input = "HTTPS://EXAMPLE.COM";
// 大文字小文字を区別せずに判定
bool isSecure = input.StartsWith("https", StringComparison.OrdinalIgnoreCase);
Console.WriteLine($"判定結果: {isSecure}");
}
}
判定結果: True
パフォーマンスと精度の観点からは、特に理由がない限り OrdinalIgnoreCase を選択することを推奨します。
理由は、カルチャ依存の比較は処理が重く、かつ特定の言語圏(トルコ語など)で予期しない挙動(いわゆる「i問題」)を引き起こす可能性があるためです。
高度な前方一致:ReadOnlySpanによる高速化
最新の .NET (特に .NET Core 以降や .NET 5/6/7/8/9)では、パフォーマンスが重視される場面において string ではなく ReadOnlySpan<char> を活用する手法が普及しています。
Spanを活用するメリット
通常の文字列操作では、部分文字列を抽出する際に新しい文字列オブジェクトがメモリ(ヒープ)上に生成されます。
しかし、ReadOnlySpan<char> を使用すると、メモリの割り当て(アロケーション)を発生させずに文字列の一部を参照できるため、ガベージコレクション(GC)の負荷を大幅に軽減できます。
Spanを用いたStartsWithの実装
大量のログデータ解析や、高頻度で呼ばれるAPIの内部処理などでは、以下のように AsSpan() を組み合わせて判定を行います。
using System;
public class Program
{
public static void Main()
{
string longData = "LOG_2026_02_21: User logged in.";
// 文字列をSpanとして扱う
ReadOnlySpan<char> span = longData.AsSpan();
// Spanに対して前方一致判定を行う
if (span.StartsWith("LOG_"))
{
Console.WriteLine("ログデータの形式が正しいです。");
}
// 指定した範囲(スライス)に対してもアロケーションなしで実行可能
if (span.Slice(4, 4).StartsWith("2026"))
{
Console.WriteLine("2026年のログです。");
}
}
}
ログデータの形式が正しいです。
2026年のログです。
span.Slice(4, 4) を使用しても、新しい文字列が作られているわけではなく、元の文字列の特定の範囲を「覗き見ている」だけです。
この ゼロアロケーション という概念は、モダンC#における高速化の鉄則です。
他の手法との比較:IndexOfや正規表現
前方一致を判定する方法は StartsWith だけではありません。
状況に応じて他の手段が適している場合もあります。
IndexOf メソッド
str.IndexOf("target") == 0 という記述で前方一致を判定することも可能ですが、これは現在では推奨されません。
IndexOf は文字列全体を検索しようとするため、StartsWith よりも非効率になる可能性が高いからです。
意図を明確にするためにも StartsWith を使いましょう。
正規表現 (Regex)
複雑なパターン(例:「数字4桁で始まる場合」など)を判定したい場合は、正規表現を使用します。
using System;
using System.Text.RegularExpressions;
public class Program
{
public static void Main()
{
string code = "1234-ABCD";
// 行頭を示す ^ を使用した前方一致パターン
bool isMatch = Regex.IsMatch(code, @"^\d{4}");
Console.WriteLine($"正規表現判定結果: {isMatch}");
}
}
正規表現判定結果: True
ただし、正規表現は StartsWith に比べて 圧倒的に処理が重い ため、単純な文字列比較で済む場合は必ず StartsWith を選択してください。
特殊なケース:nullや空文字の扱い
実務でバグを生みやすいのが、対象の文字列が null や空文字(string.Empty)の場合の挙動です。
| 呼び出し元の状態 | 引数の状態 | 結果 | 備考 |
|---|---|---|---|
| “Hello” | “” (空文字) | true | 仕様上、空文字で始まっていると見なされる |
| “” (空文字) | “” (空文字) | true | 同上 |
null | “Any” | 例外発生 | NullReferenceException |
| “Any” | null | 例外発生 | ArgumentNullException |
null合体演算子や静的メソッドを活用して、安全に判定を行うことが重要です。
string? input = GetNullableString();
// 安全な判定方法の例
if (input?.StartsWith("Target") ?? false)
{
// inputがnullでなく、かつ"Target"で始まる場合のみ実行
}
パフォーマンスベンチマークの視点
開発者がよく迷う点として、「自分で最初の数文字を比較するのと、StartsWithを呼ぶのではどちらが速いか」というものがあります。
例えば str.Length >= 3 && str[0] == 'A' && str[1] == 'B' && str[2] == 'C' のようなコードです。
結論として、現代の .NET においては StartsWith の内部実装は極めて高度に最適化されています。
内部では SIMD (Single Instruction, Multiple Data) と呼ばれる CPU 命令セットを利用し、複数の文字を一度に比較する処理が行われています。
そのため、手動で文字を1つずつ比較するよりも、標準メソッドに任せるほうが安全かつ高速であるケースがほとんどです。
特に、.NET 8 以降では、文字列比較のアルゴリズムがさらに強化されており、開発者はコードの可読性を犠牲にしてまで独自の比較ロジックを書く必要はなくなっています。
まとめ
C#における前方一致判定は、単純に見えて奥の深いトピックです。
- 基本:直感的な
StartsWithメソッドを使用する。 - 正確性:大文字小文字を区別しない場合は、必ず
StringComparison.OrdinalIgnoreCaseを明示する。 - 安全性:
nullチェックを怠らず、必要に応じてエルビス演算子(?.)を活用する。 - 最適化:パフォーマンスが極めて重要な箇所では
ReadOnlySpan<char>によるゼロアロケーションな比較を検討する。
これらのポイントを抑えることで、バグが少なく、かつメンテナンス性とパフォーマンスに優れたコードを記述できるようになります。
まずは標準的な StartsWith を正しく使いこなすことから始め、必要に応じて最新の高速化技術を取り入れてみてください。






