シフト JISで使用できない文字の入力を禁止するには?

文書番号 : 40518     文書種別 : 使用方法     登録日 : 2017/07/26     最終更新日 : 2017/07/26
文書を印刷する
対象製品
MultiRow for Windows Forms 10.0J
詳細
サロゲートペア、結合文字、JIS2004のようにシフトJISで使用できないUnicode文字の入力を禁止するには、入力された文字列とシフトJISへの変換結果を比較し、一致しない場合に検証エラーにします。

次のコードは、GcMultiRowコントロールのセル検証イベントを使用した実装例です。たとえば、JIS2004を入力できる環境で「もりおうがい」と入力し、「森おう外(おうは変換候補の一覧から環境依存文字を選択)」と変換し、Enterキーでセルの編集を確定、Tabキーまたはマウス操作で次のセルに移動しようとすると、セルの検証がエラーになります。

[Visual Basic]
Imports System.Globalization
Imports System.Text
Imports GrapeCity.Win.MultiRow

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    GcMultiRow1.Template = Template.Default
End Sub

Private Sub GcMultiRow1_CellValidating(ByVal sender As System.Object, ByVal e As CellValidatingEventArgs) Handles GcMultiRow1.CellValidating
    Dim gcMultiRow As GcMultiRow = TryCast(sender, GcMultiRow)

    If TypeOf gcMultiRow.Rows(e.RowIndex).Cells(e.CellIndex) Is TextBoxCell AndAlso e.FormattedValue IsNot Nothing Then
        Dim sjis As Encoding = Encoding.GetEncoding("Shift_JIS")
        Dim formattedString As String = DirectCast(e.FormattedValue, String)
        Console.WriteLine(formattedString)
        Dim bytes As Byte() = sjis.GetBytes(formattedString)
        Dim sjisString As String = sjis.GetString(bytes)

        If Not sjisString = formattedString Then
            Dim diff As Integer = CompareStrings(formattedString, sjisString)
            Dim invalidString As String = StringInfo.GetNextTextElement(formattedString, diff)
            gcMultiRow.Rows(e.RowIndex).Cells(e.CellIndex).ErrorText = String.Format("'{0}' はシフトJISで使用できない文字です。", invalidString)
            e.Cancel = True
        End If
    End If
End Sub

''' <summary>
''' 指定した 2 つの String オブジェクトを比較し、最初に見つかった異なる文字の位置を示す整数を返します。
''' </summary>
''' <param name="strA">第1の String</param>
''' <param name="strB">第2の String</param>
''' <returns>最初に見つかった異なる文字の位置。文字列が同じ場合は-1。</returns>
Private Function CompareStrings(ByVal strA As String, ByVal strB As String) As Integer
    Dim a As Char() = strA.ToCharArray()
    Dim b As Char() = strB.ToCharArray()

    For i As Integer = 0 To a.Length - 1
        If Not a(i) = b(i) Then Return i
    Next

    Return -1
End Function

Private Sub GcMultiRow1_CellValidated(ByVal sender As System.Object, ByVal e As GrapeCity.Win.MultiRow.CellEventArgs) Handles GcMultiRow1.CellValidated
    Dim gcMultiRow As GcMultiRow = TryCast(sender, GcMultiRow)
    gcMultiRow.Rows(e.RowIndex).Cells(e.CellIndex).ErrorText = ""
End Sub

Private Sub GcMultiRow1_EditingControlShowing(ByVal sender As System.Object, ByVal e As EditingControlShowingEventArgs) Handles GcMultiRow1.EditingControlShowing
    If TypeOf e.Control Is TextBoxEditingControl Then
        RemoveHandler e.Control.TextChanged, AddressOf TextBoxEditingControl_TextChanged
        AddHandler e.Control.TextChanged, AddressOf TextBoxEditingControl_TextChanged
    End If
End Sub

Private Sub TextBoxEditingControl_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
    Dim textBoxEditingControl As TextBoxEditingControl = TryCast(sender, TextBoxEditingControl)
    textBoxEditingControl.GcMultiRow.CurrentCell.ErrorText = ""
End Sub

[C#]
using System.Globalization;
using GrapeCity.Win.MultiRow;

private void Form1_Load(object sender, EventArgs e)
{
    gcMultiRow1.Template = Template.Default;
    gcMultiRow1.CellValidating += new EventHandler<CellValidatingEventArgs>(gcMultiRow1_CellValidating);
    gcMultiRow1.CellValidated += new EventHandler<CellEventArgs>(gcMultiRow1_CellValidated);
    gcMultiRow1.EditingControlShowing += new EventHandler<EditingControlShowingEventArgs>(gcMultiRow1_EditingControlShowing);
}

private void gcMultiRow1_CellValidating(object sender, GrapeCity.Win.MultiRow.CellValidatingEventArgs e)
{
    GcMultiRow gcMultiRow = sender as GcMultiRow;

    if (gcMultiRow.Rows[e.RowIndex].Cells[e.CellIndex] is TextBoxCell && e.FormattedValue != null)
    {
        Encoding sjis = Encoding.GetEncoding("Shift_JIS");
        string formattedString = (string)e.FormattedValue;
        byte[] bytes = sjis.GetBytes(formattedString);
        string sjisString = sjis.GetString(bytes);
        if (sjisString != formattedString)
        {
            int diff = CompareStrings(formattedString, sjisString);
            string invalidString = StringInfo.GetNextTextElement(formattedString, diff);
            gcMultiRow.Rows[e.RowIndex].Cells[e.CellIndex].ErrorText = string.Format("'{0}' はシフトJISで使用できない文字です。", invalidString);
            e.Cancel = true;
        }
    }
}

/// <summary>
/// 指定した 2 つの String オブジェクトを比較し、最初に見つかった異なる文字の位置を示す整数を返します。
/// </summary>
/// <param name="strA">第1の String</param>
/// <param name="strB">第2の String</param>
/// <returns>最初に見つかった異なる文字の位置。文字列が同じ場合は-1。</returns>
private int CompareStrings(string strA, string strB)
{
    char[] a = strA.ToCharArray();
    char[] b = strB.ToCharArray();

    for (int i = 0; i < a.Length; i++)
    {
        if (a[i] != b[i]) return i;
    }
    return -1;
}

private void gcMultiRow1_CellValidated(object sender, CellEventArgs e)
{
    GcMultiRow gcMultiRow = sender as GcMultiRow;
    gcMultiRow.Rows[e.RowIndex].Cells[e.CellIndex].ErrorText = "";
}

private void gcMultiRow1_EditingControlShowing(object sender, EditingControlShowingEventArgs e)
{
    if (e.Control is TextBoxEditingControl)
    {
        e.Control.TextChanged -= new EventHandler(TextBoxEditingControl_TextChanged);
        e.Control.TextChanged += new EventHandler(TextBoxEditingControl_TextChanged);
    }
}

private void TextBoxEditingControl_TextChanged(object sender, EventArgs e)
{
    TextBoxEditingControl textBoxEditingControl = sender as TextBoxEditingControl;
    textBoxEditingControl.GcMultiRow.CurrentCell.ErrorText = "";
}

参考:
InputManCellのGcTextBoxCellを使用すると、数字やカナ、アルファベットや記号などのほかに、以下の文字に対して入力を制限することができます。
文字の入力制限は、GcTextBoxCell.Formatプロパティに該当するキーワードを設定することで実現します。
  • サロゲート ペア文字
  • 2バイト文字(サロゲート ペア文字を除いた全角文字)
  • JIS X 0208で構成された文字
  • Shift JIS(CP932)で構成された文字
  • IVS(Ideographic Variation Sequence)文字