C#で文字列と数値を相互に変換する場面は、フォーム入力の検証、ファイルやAPIの入出力、ログ出力や画面表示など多岐にわたります。
本稿では、初心者の方でも迷わないように、Parse/TryParse/ToStringの使い分けから、例外やロケール対応(NumberStyles/CultureInfo)まで、具体例と実行結果付きで丁寧に解説します。
C#の文字列⇄数値変換の基本(Parse/TryParse/ToString)
文字列→数値の基本方針と選び方(ParseとTryParseの違い)
文字列から数値へは大きく2通りの入り口があります。
- Parse系:
int.Parse
,double.Parse
,decimal.Parse
など。失敗時は例外を投げます。 - TryParse系:
int.TryParse
,double.TryParse
,decimal.TryParse
など。失敗時は例外を投げず、bool
で成否を返します。
ユーザー入力や外部データのように「失敗する可能性がある」場合はTryParseを優先し、事前に「必ず正しい形式だ」と分かっている場合のみParseを使うのが基本方針です。
以下は違いが分かる最小例です。
using System;
class Program
{
static void Main()
{
string ok = "123";
string ng = "abc";
// Parse: 成功 -> 値、失敗 -> 例外
Console.WriteLine(int.Parse(ok)); // 123
try
{
Console.WriteLine(int.Parse(ng));
}
catch (Exception ex)
{
Console.WriteLine(ex.GetType().Name); // 何の例外かを出力
}
// TryParse: 成否をboolで返し、失敗しても例外なし
bool success = int.TryParse(ng, out int value);
Console.WriteLine($"TryParse={success}, value={value}");
}
}
123
FormatException
TryParse=False, value=0
数値→文字列の基本方針(ToStringと書式指定の概要)
数値から文字列へはToString
が基本です。
ToString()
は引数に「書式指定子」と「カルチャ情報」を取れます。
num.ToString("N2", CultureInfo.GetCultureInfo("en-US"))
のように書くと、桁区切りや小数点の位置、ロケールごとの表記に合わせて文字列化できます。- 書式指定子には、標準書式(
G, N, F, C, P
など)とカスタム書式(例:#,0.00
,00000
)があります。
Parseの使い方と注意点(int.Parse/double.Parse/decimal.Parse)
Parseが投げる例外(FormatException/OverflowException)
Parseは「形式が不正」や「範囲外」のときに例外を投げます。
using System;
class Program
{
static void Main()
{
// 形式が不正 -> FormatException
try
{
var x = int.Parse("12x3");
}
catch (Exception ex)
{
Console.WriteLine(ex.GetType().Name);
}
// 範囲外 -> OverflowException (intの最大値は 2,147,483,647)
try
{
var y = int.Parse("2147483648");
}
catch (Exception ex)
{
Console.WriteLine(ex.GetType().Name);
}
}
}
FormatException
OverflowException
前後の空白やタブの扱い(Trimの活用)
多くのParseは前後の空白(タブや改行を含む)を既定で許容しますが、入力が不安定な場合はTrim()
で明示的に削除しておくと安全です。
using System;
class Program
{
static void Main()
{
string s = "\t 123 \r\n";
int n1 = int.Parse(s); // OK: 既定で前後の空白を許容
int n2 = int.Parse(s.Trim()); // もちろんOK
Console.WriteLine(n1);
Console.WriteLine(n2);
}
}
123
123
符号・小数点・桁区切りの解釈(NumberStyles/CultureInfo)
数値の表記はカルチャ(ロケール)によって異なります。
例えばドイツ(de-DE
)では小数点が,
、桁区切りが.
です。
CultureInfo
とNumberStyles
を併用すると、意図通りに解釈できます。
using System;
using System.Globalization;
class Program
{
static void Main()
{
// de-DE: "1.234,56" => 1234.56
var de = new CultureInfo("de-DE");
double d = double.Parse("1.234,56", de);
Console.WriteLine(d);
// en-USで桁区切りと符号を許容してintを解釈
var us = new CultureInfo("en-US");
int i = int.Parse("-1,234", NumberStyles.Integer | NumberStyles.AllowThousands, us);
Console.WriteLine(i);
}
}
1234.56
-1234
要点として、NumberStyles
にはAllowLeadingSign
, AllowThousands
, AllowDecimalPoint
, Currency
, Any
などがあり、何を許容するか細かく指定できます。
カルチャに応じて適切なCultureInfo
を渡してください。
TryParseの使い方とベストプラクティス
TryParseの基本シグネチャと戻り値(bool)
TryParseは以下の2系統がよく使われます。
bool int.TryParse(string? s, out int result)
bool int.TryParse(string? s, NumberStyles style, IFormatProvider? provider, out int result)
成功時はtrue
と変換後の値、失敗時はfalse
とデフォルト値(数値型は0)が返ります。
入力検証の定番パターン(ifとTryParse)
ユーザー入力検証の基本形です。
例として、複数の入力文字列を検証します。
using System;
using System.Globalization;
class Program
{
static void Main()
{
var us = new CultureInfo("en-US");
string[] inputs = { "42", " 99 ", "1,234", "abc" };
foreach (var s in inputs)
{
// 桁区切りを許容して解析
bool ok = int.TryParse(s, NumberStyles.Integer | NumberStyles.AllowThousands, us, out int value);
if (ok)
{
Console.WriteLine($"OK: {s} -> {value}");
}
else
{
Console.WriteLine($"NG: {s} は整数として無効です");
}
}
}
}
OK: 42 -> 42
OK: 99 -> 99
OK: 1,234 -> 1234
NG: abc は整数として無効です
NumberStyles/CultureInfoを指定したTryParse
通貨記号や各国の区切りに対応したい場合は、NumberStyles.Currency
や適切なCultureInfo
を指定します。
using System;
using System.Globalization;
class Program
{
static void Main()
{
bool okJp = decimal.TryParse("¥1,234", NumberStyles.Currency, new CultureInfo("ja-JP"), out decimal yen);
bool okDe = decimal.TryParse("1.234,56 €", NumberStyles.Currency, new CultureInfo("de-DE"), out decimal euro);
bool okGb = decimal.TryParse("£100.50", NumberStyles.Currency, new CultureInfo("en-GB"), out decimal gbp);
Console.WriteLine($"ja-JP: {okJp}, {yen}");
Console.WriteLine($"de-DE: {okDe}, {euro}");
Console.WriteLine($"en-GB: {okGb}, {gbp}");
}
}
ja-JP: True, 1234
de-DE: True, 1234.56
en-GB: True, 100.50
ToStringによる数値→文字列変換のやり方
標準書式指定子(G/N/F/C/Pなど)の使い分け
代表的な標準書式の概要です。
指定子 | 説明 |
---|---|
G | 一般的な最短表現(最も短い形式で表現) |
N | 数値(桁区切りあり、小数点以下の桁数を指定可能。例: N0 , N2 ) |
F | 固定小数点(桁区切りなし、小数点以下の桁数を指定可能。例: F2 ) |
C | 通貨(ロケールに応じた通貨記号を付与) |
P | パーセント(値を100倍して % を付与、小数点以下桁数を指定可能) |
D | 整数の10進数表記(整数型専用。桁数指定可能。例: D4 → 0012) |
X | 整数の16進数表記(整数型専用。大文字/小文字は X / x で切替) |
実例で確かめます。
using System;
using System.Globalization;
class Program
{
static void Main()
{
var us = new CultureInfo("en-US");
double x = 1234.567;
double ratio = 0.1234;
Console.WriteLine(x.ToString("G", us)); // 一般
Console.WriteLine(x.ToString("N2", us)); // 桁区切り + 小数2桁
Console.WriteLine(x.ToString("F2", us)); // 固定小数2桁
Console.WriteLine(x.ToString("C2", us)); // 通貨(小数2桁)
Console.WriteLine(ratio.ToString("P1", us)); // パーセント(小数1桁)
}
}
1234.567
1,234.57
1234.57
$1,234.57
12.3%
整数のゼロ埋めや16進表現も簡単です。
using System;
class Program
{
static void Main()
{
int id = 42;
Console.WriteLine(id.ToString("D5")); // 00042
Console.WriteLine(id.ToString("X")); // 2A (16進)
}
}
00042
2A
カスタム書式(桁区切り, 小数点桁数, 0埋め)
より細かい制御が必要なときはカスタム書式を使います。
0
は必ず表示、#
はあれば表示、,
は桁区切り、.
は小数点です。
using System;
using System.Globalization;
class Program
{
static void Main()
{
var us = new CultureInfo("en-US");
double amount = 1234.5;
int seq = 42;
Console.WriteLine(amount.ToString("#,0.00", us)); // 1,234.50
Console.WriteLine(amount.ToString("0.###", us)); // 1234.5
Console.WriteLine(seq.ToString("00000")); // 00042
}
}
1,234.50
1234.5
00042
CultureInfoでロケール別の文字列を出力
同じ値でもカルチャにより見た目が変わります。
using System;
using System.Globalization;
class Program
{
static void Main()
{
double v = 1234.56;
decimal price = 1234m;
var us = new CultureInfo("en-US");
var de = new CultureInfo("de-DE");
var jp = new CultureInfo("ja-JP");
// 数値(N2)
Console.WriteLine(v.ToString("N2", us)); // en-US
Console.WriteLine(v.ToString("N2", de)); // de-DE
Console.WriteLine(v.ToString("N2", jp)); // ja-JP
// 通貨(C)
Console.WriteLine(price.ToString("C", us)); // en-US
Console.WriteLine(price.ToString("C", de)); // de-DE
Console.WriteLine(price.ToString("C", jp)); // ja-JP (円は小数なし)
}
}
1,234.56
1.234,56
1,234.56
$1,234.00
1.234,00 €
¥1,234
型別の注意点と精度(int/long/float/double/decimal)
int/longの範囲とオーバーフロー対策
整数型は取り得る範囲が決まっています。
Parse
は範囲外をOverflowException
として検出します。
自前演算のオーバーフローはchecked
で検出できます。
using System;
class Program
{
static void Main()
{
Console.WriteLine($"int: {int.MinValue} .. {int.MaxValue}");
Console.WriteLine($"long: {long.MinValue} .. {long.MaxValue}");
try
{
checked
{
int x = int.MaxValue;
x += 1; // ここでOverflowException
}
}
catch (Exception ex)
{
Console.WriteLine(ex.GetType().Name);
}
}
}
int: -2147483648 .. 2147483647
long: -9223372036854775808 .. 9223372036854775807
OverflowException
float/doubleの丸め誤差とToStringの注意点
float/double
は2進浮動小数のため、10進小数を正確に表せない場合があります。
0.1 + 0.2
の例が典型です。
表示書式により誤差が見えたり隠れたりします。
using System;
using System.Globalization;
class Program
{
static void Main()
{
var inv = CultureInfo.InvariantCulture;
double d = 0.1 + 0.2;
Console.WriteLine(d.ToString("G", inv)); // 一般表記(見た目は0.3)
Console.WriteLine(d.ToString("R", inv)); // 厳密(ラウンドトリップ)
// 近年の.NETでは "G17" も厳密表現として有効
Console.WriteLine(d.ToString("G17", inv));
}
}
0.3
0.30000000000000004
0.30000000000000004
表示上は四捨五入されても中身はわずかにズレるため、金額など誤差が許されない用途ではdecimal
を使います。
decimalでの金額計算とParse/TryParseのコツ
decimal
は10進小数を高精度で扱えるため、金額・個数・率などに適しています。
通貨の解析にはNumberStyles.Currency
と適切なCultureInfo
を組み合わせます。
using System;
using System.Globalization;
class Program
{
static void Main()
{
// 計算の安定性
decimal a = 0.1m + 0.2m;
Console.WriteLine(a); // 0.3
// 解析のコツ
var us = new CultureInfo("en-US");
bool ok = decimal.TryParse("$1,234.50", NumberStyles.Currency, us, out decimal price);
Console.WriteLine($"{ok}, {price}");
}
}
0.3
True, 1234.50
エラー対策とまとめ(初心者が押さえるポイント)
よくある失敗と対処法(全角・空白・桁区切り)
実務では入力が「きれい」とは限りません。
よくある落とし穴と対処の要点です。
- 全角数字・全角記号: そのままでは失敗することがあります。互換正規化(FormKC)で半角に寄せてから解析すると安定します。
- 前後や途中の空白:
Trim()
やNumberStyles
で許容。意図しない空白が混ざる場合は前処理で除去を検討します。 - 桁区切り・通貨記号:
NumberStyles.AllowThousands
やNumberStyles.Currency
を使い、CultureInfo
を正しく指定します。
例: 全角の数字とカンマを正規化してから解析するパターンです。
using System;
using System.Globalization;
using System.Text;
class Program
{
static void Main()
{
string raw = " 123,456 "; // 全角空白・全角数字・全角カンマ
string normalized = raw.Normalize(NormalizationForm.FormKC).Trim(); // 半角化 + 前後空白除去
bool ok = int.TryParse(
normalized,
NumberStyles.Integer | NumberStyles.AllowThousands,
new CultureInfo("ja-JP"),
out int value);
Console.WriteLine($"{ok}, {value}");
}
}
True, 123456
使い分けの結論(Parse/TryParse/ToString)
- 文字列→数値: 未検証の入力や外部データはTryParseで安全に。形式保証済みの内部データのみParseを使う。
- 数値→文字列: 画面やログの表示はToStringに書式を付け、必要に応じてCultureInfoを明示する。金額はdecimalで扱い、通貨書式(C)を活用する。
- ロケール差異: 解析・表示の双方でCultureInfoを意識する。異文化圏のデータやAPI連携では特に重要。
覚えておきたいキーワード(NumberStyles/CultureInfo/書式指定子)
- NumberStyles: 入力の許容範囲(符号、桁区切り、小数点、通貨記号、空白など)を制御。
- CultureInfo: 小数点や桁区切り、通貨/%記号の位置など、ロケール固有のルールを提供。
- 書式指定子: 標準(G/N/F/C/P/D/Xなど)とカスタム(#,0.00や00000など)で出力の見た目を制御。
まとめ
C#の文字列⇄数値変換は、Parse/TryParse/ToStringの3本柱を場面に応じて使い分けるのが基本です。
未検証の入力はTryParseで堅牢に受け止め、内部的に正しいと分かっている場合のみParseを使います。
表示はToStringに書式とCultureInfoを合わせて、読みやすく・誤解のない表記に整えます。
特に、金額はdecimal、各国表記はCultureInfo、入力の多様性にはNumberStylesや正規化で備えると安心です。
これらのポイントを押さえれば、日常の開発で困ることは大幅に減るはずです。