如何使用C#检测句子间的单词与字母差异?
C#实现句子间差异检测的方法
要实现句子间的单词/字符层面差异检测,可以分两步处理:先做单词级对比,再对有差异的单词做字符级对比。以下是具体实现方案:
基础实现(按位置逐词对比)
这种方式适合句子结构基本一致,仅部分单词/字符有修改的场景。
1. 单词级差异检测方法
将句子拆分为单词列表,按位置逐词对比,记录不同的单词对:
using System; using System.Collections.Generic; using System.Linq; public static class DifferenceDetector { public static List<Tuple<string, string>> GetWordDifferences(string sentence1, string sentence2) { var words1 = sentence1.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries); var words2 = sentence2.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries); var differences = new List<Tuple<string, string>>(); int maxLength = Math.Max(words1.Length, words2.Length); for (int i = 0; i < maxLength; i++) { string word1 = i < words1.Length ? words1[i] : string.Empty; string word2 = i < words2.Length ? words2[i] : string.Empty; if (word1 != word2) { differences.Add(Tuple.Create(word1, word2)); } } return differences; } }
2. 字符级差异检测方法
针对有差异的单词,逐字符对比记录不同的字符对:
public static List<Tuple<char, char>> GetCharacterDifferences(string word1, string word2) { var differences = new List<Tuple<char, char>>(); int maxLength = Math.Max(word1.Length, word2.Length); for (int i = 0; i < maxLength; i++) { char c1 = i < word1.Length ? word1[i] : '\0'; char c2 = i < word2.Length ? word2[i] : '\0'; if (c1 != c2) { differences.Add(Tuple.Create(c1, c2)); } } return differences; }
3. 组合调用示例
将两个方法结合,输出完整的差异信息:
public static void DetectAndPrintDifferences(string sentence1, string sentence2) { var wordDiffs = GetWordDifferences(sentence1, sentence2); Console.WriteLine("单词层面差异:"); foreach (var diff in wordDiffs) { Console.WriteLine($"\"{diff.Item1}\" vs \"{diff.Item2}\""); if (!string.IsNullOrEmpty(diff.Item1) && !string.IsNullOrEmpty(diff.Item2)) { var charDiffs = GetCharacterDifferences(diff.Item1, diff.Item2); Console.WriteLine(" 字符层面差异:"); foreach (var charDiff in charDiffs) { Console.WriteLine($" '{charDiff.Item1}' vs '{charDiff.Item2}'"); } } } } // 测试示例 DetectAndPrintDifferences("this is my book", "this is may book"); DetectAndPrintDifferences("how are this cook", "hope and this cook");
测试第一组句子会输出:
单词层面差异: "my" vs "may" 字符层面差异: 'y' vs 'a' '\0' vs 'y'
测试第二组句子会输出:
单词层面差异: "how" vs "hope" 字符层面差异: 'w' vs 'p' '\0' vs 'e' "are" vs "and" 字符层面差异: 'r' vs 'n'
进阶实现(基于LCS处理单词顺序变化)
如果句子存在单词顺序调换、新增/删除单词的情况,可以用**最长公共子序列(LCS)**算法来更准确识别差异类型(新增、删除、修改):
public static List<(string OldWord, string NewWord, string ChangeType)> GetWordDifferencesWithLCS(string sentence1, string sentence2) { var words1 = sentence1.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries); var words2 = sentence2.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries); int[,] lcsTable = new int[words1.Length + 1, words2.Length + 1]; // 构建LCS表 for (int i = 1; i <= words1.Length; i++) { for (int j = 1; j <= words2.Length; j++) { if (words1[i-1] == words2[j-1]) { lcsTable[i,j] = lcsTable[i-1,j-1] + 1; } else { lcsTable[i,j] = Math.Max(lcsTable[i-1,j], lcsTable[i,j-1]); } } } var differences = new List<(string, string, string)>(); int iIndex = words1.Length; int jIndex = words2.Length; // 回溯LCS表,识别差异类型 while (iIndex > 0 || jIndex > 0) { if (iIndex > 0 && jIndex > 0 && words1[iIndex-1] == words2[jIndex-1]) { iIndex--; jIndex--; } else if (jIndex > 0 && (iIndex == 0 || lcsTable[iIndex,jIndex-1] >= lcsTable[iIndex-1,jIndex])) { differences.Add((string.Empty, words2[jIndex-1], "新增")); jIndex--; } else if (iIndex > 0 && (jIndex == 0 || lcsTable[iIndex-1,jIndex] > lcsTable[iIndex,jIndex-1])) { differences.Add((words1[iIndex-1], string.Empty, "删除")); iIndex--; } else { differences.Add((words1[iIndex-1], words2[jIndex-1], "修改")); iIndex--; jIndex--; } } differences.Reverse(); return differences; }
内容的提问来源于stack exchange,提问作者barteloma
相关产品推荐
相关产品推荐

