ユーザーが既存のテキストを再入力する場合は、単純なテキスト(1つの文字/数字を表す1つの文字など)のインデックスベースの比較を行うのと同じくらい簡単である必要があります。または、以下の例のようにStringInfo.GetTextElementEnumeratorを使用できます。
最初にテキストを入力してからエラーの数を確認するようにユーザーに依頼する場合は、レーベンシュタイン距離を使用できます(実装と説明については、http://www.dotnetperls.com/levenshteinを参照してください)。レーベンシュタイン距離は、基本的に、ある文字列を別の文字列のように見せるために必要な編集の量です。
1文字を表すために2文字以上が必要な、文字とサロゲートペアを組み合わせたUnicodeをサポートするように指示された場合、実装は技術的に不完全になることに注意してください。後者の場合、次のようにStringInfo.GetTextElementEnumeratorを使用してテキスト要素を生成および比較するように、その実装を変更できます。
using System;
using System.Collections.Generic;
using System.Globalization;
/// <summary>
/// Contains approximate string matching
/// </summary>
internal static class LevenshteinDistance
{
/// <summary>
/// Compute the distance between two strings using text elements.
/// </summary>
public static int ComputeByTextElements(string s, string t) {
string[] strA = GetTextElements(s),
strB = GetTextElements(t);
int n = strA.Length;
int m = strB.Length;
var d = new int[n + 1,m + 1];
// Step 1
if (n == 0) {
return m;
}
if (m == 0) {
return n;
}
// Step 2
for (int i = 0; i <= n; d[i, 0] = i++) {}
for (int j = 0; j <= m; d[0, j] = j++) {}
// Step 3
for (int i = 1; i <= n; i++) {
//Step 4
for (int j = 1; j <= m; j++) {
// Step 5
int cost = (strB[j - 1] == strA[i - 1]) ? 0 : 1;
// Step 6
d[i, j] = Math.Min(
Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1),
d[i - 1, j - 1] + cost);
}
}
// Step 7
return d[n, m];
}
private static string[] GetTextElements(string str) {
if (string.IsNullOrEmpty(str)) {
return new string[] {};
}
var result = new List<string>();
var enumerator = StringInfo.GetTextElementEnumerator(str);
while (enumerator.MoveNext()) {
result.Add(enumerator.Current.ToString());
}
return result.ToArray();
}
}
また、上記のソリューションでは大文字と小文字が区別されるため、大文字と小文字を区別しないレーベンシュタイン距離の計算が必要な場合は、入力をすべて大文字または小文字にすることをお勧めします。
あなたの編集について
文字とサロゲートペアの組み合わせを考慮していないため、(文字)インデックスベースの比較には同意しません。入力するテキストを表すテキスト要素の配列を作成し、キーストロークごとに、入力した入力のテキスト要素の配列(または速度を最適化するためのキャッシュ実装による比較用のサブセット)を作成して比較します。