我有以下任务:开发一个程序,其中有一个示例文本块,应该由用户输入。用户在测试期间做的任何拼写错误都被注册。基本上我可以将每个键入的char与基于示例的char进行比较但是在这种“天真”的方法中有一个重要的流程 - 如果用户错误地输入的字母多于整个字符串,或者在字符串之间插入的空格比应该更多,在这样的情况下其他比较将是错误的,因为额外的错误插入添加了索引偏移。我想到设计某种解析器,其中每个字符串(甚至一个字符)被标记化,并且比较是“char-wise” “而不是”索引方式“。但在我看来,这对于这样的任务来说就像是一种过度杀伤。我希望能够找到可能有助于解决这类问题的现有算法。
此外,我不确定这个问题是否更符合“程序员”网站的精神,所以我也将它发布在那里。
更新
我忘记提到的另一个重要细节是必须对每个输入进行评估,而不是在任务结束时,因为它包括输入时间记录等...
答案 0 :(得分:0)
如果用户正在重新输入现有文本,那么它应该像对简单文本进行基于索引的比较一样简单(一个字符代表一个字母/数字等),或者您可以使用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距离计算,您可能希望将输入全部为大写或小写。
关于您的修改
我不满足于基于(字符)索引的比较,因为它没有考虑组合字符和代理对。我将建立一个表示要输入的文本的文本元素数组,然后按键创建一个数组(或通过一些缓存实现进行比较的子集,以优化速度)输入的文本元素并进行比较。 / p>