方法 : Web コントロールでの数値のユーザー入力を数値に変換する
更新 : 2007 年 11 月
Web ページは世界中どこでも表示可能なため、ユーザーは TextBox コントロールの中に多種多様な形式で数値データを入力する可能性があります。このため、Web ページのユーザーのロケールとカルチャを判別することは非常に重要です。ユーザー入力を解析するとき、ユーザーのロケールとカルチャによって定義された書式指定規則を適用できます。
Web TextBox コントロールでの数値入力を数値に変換するには
HttpRequest.UserLanguages プロパティによって返された文字列配列にデータが含まれているかどうかを判別します。含まれない場合は、手順 6. に進みます。
UserLanguages プロパティによって返された文字列配列にデータが含まれる場合は、その最初の要素を取得します。最初の要素は、ユーザーの既定の言語と地域、または優先される言語と地域を表します。
CultureInfo.CultureInfo(String, Boolean) コンストラクタを呼び出すことにより、ユーザーが選択したカルチャを表す CultureInfo オブジェクトをインスタンス化します。
ユーザー入力の変換先となる数値型の TryParse メソッドまたは Parse メソッドを呼び出します。TryParse メソッドまたは Parse メソッドの provider パラメータを指定するオーバーロードを使用して、次のいずれかを渡します。
手順 3. で作成した CultureInfo オブジェクト。
手順 3. で作成した CultureInfo オブジェクトの NumberFormat プロパティによって返される NumberFormatInfo オブジェクト。
変換が失敗した場合、UserLanguages プロパティによって返される文字列配列内の他の要素ごとに手順 2. から 4. を繰り返します。
変換が引き続き失敗する場合、または UserLanguages プロパティによって返された文字列配列が空の場合には、CultureInfo.InvariantCulture プロパティによって返されるインバリアント カルチャを使って文字列を解析します。
使用例
次の例は、TextBox コントロールに数値を入力するようユーザーに要求して、それを数値に変換する Web フォームの完全な分離コード ページです。その後、その数値を 2 倍にして、元の入力と同じ書式指定規則を使って表示します。
Imports System.Globalization
Partial Class NumericUserInput
Inherits System.Web.UI.Page
Protected Sub OKButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles OKButton.Click
Dim locale As String
Dim culture As CultureInfo = Nothing
Dim number As Double
Dim result As Boolean
' Exit if input is absent.
If String.IsNullOrEmpty(Me.NumericString.Text) Then Exit Sub
' Hide form elements.
Me.NumericInput.Visible = False
' Get user culture/region
If Not (Request.UserLanguages.Length = 0 OrElse String.IsNullOrEmpty(Request.UserLanguages(0))) Then
Try
locale = Request.UserLanguages(0)
culture = New CultureInfo(locale, False)
' Parse input using user culture.
result = Double.TryParse(Me.NumericString.Text, NumberStyles.Any, culture.NumberFormat, number)
Catch
End Try
' If parse fails, parse input using any additional languages.
If Not result Then
If Request.UserLanguages.Length > 1 Then
For ctr As Integer = 1 To Request.UserLanguages.Length - 1
Try
locale = Request.UserLanguages(ctr)
' Remove quality specifier, if present.
locale = Left(locale, InStr(locale, ";") - 1)
culture = New CultureInfo(Request.UserLanguages(ctr), False)
result = Double.TryParse(Me.NumericString.Text, NumberStyles.Any, culture.NumberFormat, number)
If result Then Exit For
Catch
End Try
Next
End If
End If
End If
' If parse operation fails, use invariant culture.
If Not result Then
result = Double.TryParse(Me.NumericString.Text, NumberStyles.Any, CultureInfo.InvariantCulture, number)
End If
' Double result
number *= 2
' Display result to user.
If result Then
Response.Write("<P />")
Response.Write(Server.HtmlEncode(Me.NumericString.Text) + " * 2 = " + number.ToString("N", culture) + "<BR />")
Else
' Unhide form.
Me.NumericInput.Visible = True
Response.Write("<P />")
Response.Write("Unable to recognize " + Server.HtmlEncode(Me.NumericString.Text))
End If
End Sub
End Class
using System;
using System.Globalization;
partial class NumericUserInput : System.Web.UI.Page
{
protected void OKButton_Click(object sender, EventArgs e)
{
string locale;
CultureInfo culture = null;
double number = 0;
bool result = false;
// Exit if input is absent.
if (String.IsNullOrEmpty(this.NumericString.Text)) return;
// Hide form elements.
this.NumericInput.Visible = false;
// Get user culture/region
if (!(Request.UserLanguages.Length == 0 || String.IsNullOrEmpty(Request.UserLanguages[0])))
{
try
{
locale = Request.UserLanguages[0];
culture = new CultureInfo(locale, false);
// Parse input using user culture.
result = Double.TryParse(this.NumericString.Text, NumberStyles.Any,
culture.NumberFormat, out number);
}
catch { }
// If parse fails, parse input using any additional languages.
if (!result)
{
if (Request.UserLanguages.Length > 1)
{
for (int ctr = 1; ctr <= Request.UserLanguages.Length - 1; ctr++)
{
try
{
locale = Request.UserLanguages[ctr];
// Remove quality specifier, if present.
locale = locale.Substring(1, locale.IndexOf(';') - 1);
culture = new CultureInfo(Request.UserLanguages[ctr], false);
result = Double.TryParse(this.NumericString.Text, NumberStyles.Any, culture.NumberFormat, out number);
if (result) break;
}
catch { }
}
}
}
}
// If parse operation fails, use invariant culture.
if (!result)
result = Double.TryParse(this.NumericString.Text, NumberStyles.Any, CultureInfo.InvariantCulture, out number);
// Double result.
number *= 2;
// Display result to user.
if (result)
{
Response.Write("<P />");
Response.Write(Server.HtmlEncode(this.NumericString.Text) + " * 2 = " + number.ToString("N", culture) + "<BR />");
}
else
{
// Unhide form.
this.NumericInput.Visible = true;
Response.Write("<P />");
Response.Write("Unable to recognize " + Server.HtmlEncode(this.NumericString.Text));
}
}
}
HttpRequest.UserLanguages プロパティには、HTTP 要求の Accept-Language ヘッダーに含まれるカルチャ名からデータが入ります。ただし、すべてのブラウザの要求に Accept-Language ヘッダーが含まれるとは限りません。ユーザーがヘッダーを完全に禁止する場合もあります。このため、ユーザー入力を解析する際にはフォールバック カルチャが重要になります。通常、フォールバック カルチャは、CultureInfo.InvariantCulture によって返されるインバリアント カルチャです。また、テキスト ボックスへの入力によってユーザーがカルチャ名を Internet Explorer に提供する場合もありますが、無効なカルチャ名が指定される可能性があります。このため、CultureInfo オブジェクトをインスタンス化する際には、例外処理が重要になります。
Internet Explorer によって送信された HTTP 要求から取得される HttpRequest.UserLanguages 配列には、ユーザー側の優先度設定の順序でデータが入ります。配列の先頭の要素には、ユーザーの最優先カルチャ/地域の名前が格納されます。何らかの追加項目が配列に含まれる場合、Internet Explorer はそれらに任意のクオリティ識別子を割り当てます。この識別子はセミコロンによってカルチャから区切られます。たとえば、fr-FR カルチャの項目は fr-FR;q=0.7 という形式になります。
この例では、useUserOverride パラメータを false に設定して CultureInfo コンストラクタを呼び出し、新しい CultureInfo オブジェクトを作成します。これによって、カルチャ名がサーバー上の既定のカルチャ名である場合、クラス コンストラクタによって作成される新しい CultureInfo オブジェクトにはカルチャの既定の設定が含まれ、サーバーの [地域と言語のオプション] アプリケーションを使ってオーバーライドされた設定は反映されません。通常、サーバーでオーバーライドされた設定値はユーザーのシステムに存在せず、ユーザー入力に反映されることもありません。
ユーザー入力の変換先となる数値型の Parse メソッドまたは TryParse メソッドをコードで呼び出すことができます。1 つの解析操作で解析メソッドを繰り返し呼び出す必要が生じる場合があります。したがって、解析操作が失敗した場合に false を返す TryParse メソッドの方が適切です。これに対して、Parse メソッドによって繰り返しスローされる例外を Web アプリケーションで処理する場合、コストが非常に大きくなる可能性があります。
コードのコンパイル方法
コードをコンパイルするには、既存のすべてのコードに置き換える形で、このコードを ASP.NET 分離コード ページの中にコピーします。ASP.NET Web ページには、次のコントロールを含める必要があります。
コード内で参照されない Label コントロール。その Text プロパティを "Enter a Number:" に設定します。
NumericString という名前の TextBox コントロール。
クラスの名前を、NumericUserInput から、ASP.NET ページの Page ディレクティブの Inherits 属性で定義されるクラス名に変更します。NumericInput オブジェクト参照の名前を、ASP.NET ページの form タグの id 属性で定義される名前に変更します。
セキュリティ
ユーザーが HTML ストリーム内にスクリプトを挿入するのを防ぐために、サーバー応答の中でユーザー入力を直接エコー バックしないでください。そうする代わりに、HttpServerUtility.HtmlEncode メソッドを使ってこれをエンコードする必要があります。