如果用户正在重新键入现有文本,那么它应该像对简单文本(一个字符代表一个字母/数字等)进行基于索引的比较一样简单,或者您可以使用 StringInfo.GetTextElementEnumerator 作为下面的示例。
如果您要让用户先输入文本,然后检查犯了多少错误,您可以使用 Levenshtein 距离(请参阅此处的实现和解释: http: //www.dotnetperls.com/levenshtein)。Levenshtein 距离本质上是使一个字符串看起来像另一个字符串所需的编辑量。
请注意,如果您的任务是支持 unicode 与组合字符和代理对(其中需要 2 个或更多字符来表示一个字母),那么实现在技术上将是不完整的。在后一种情况下,您可以修改该实现以使用 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();
}
}
另请注意,上述解决方案区分大小写,因此如果您需要不区分大小写的 Levenshtein 距离计算,您可能希望将输入全部设为大写或小写。
关于您的编辑
我不会满足于基于(字符)索引的比较,因为它没有考虑组合字符和代理对。我将建立一个文本元素数组,表示要输入的文本,然后每次击键创建一个数组(或子集,通过一些缓存实现进行比较以优化速度)并比较它们。