我有一个C#函数,可以逐行比较两个字符串oldString
和newString
。每个比较仅在引号内考虑案例。例如,这两行是相同的:
If Foo Then: Debug.Print "Hello World!"
If foo Then: Debug.print "Hello World!"
这两个是不平等的:
If Foo Then: Debug.Print "Hello World!"
If Foo Then: Debug.Print "hello world!"
该函数返回一个由newString
构造的新文件,但是如果行没有变化,则使用来自oldString
的行。所以如果这是oldString
:
If Foo Then
Debug.Print "Hello World!"
End If
Debug.Print "This line will be deleted soon."
这是newString
:
If foo Then
Debug.print "Hello World!"
Debug.print "This is a new line."
End If
然后该函数返回:
If Foo Then
Debug.Print "Hello World!"
Debug.print "This is a new line."
End If
目前我正在使用基于动态编程方法的代码来解决最常见的子串问题,并进行了一些简单的优化:
public static string FixCase(string oldString, string newString) {
if (string.Equals(oldString, newString, StringComparison.InvariantCulture)) {
return newString;
}
var oldLines = oldString.Split(new[] { "\r\n" }, StringSplitOptions.None).ToList();
var newLines = newString.Split(new[] { "\r\n" }, StringSplitOptions.None).ToList();
var headEqualLines = new List<string>();
var minLineCount = oldLines.Count < newLines.Count ? oldLines.Count : newLines.Count;
for (var i = 0; i < minLineCount; i++) {
if (VbaLineEqual(oldLines[i], newLines[i])) {
headEqualLines.Add(oldLines[i]);
} else {
break;
}
}
oldLines.RemoveRange(0, headEqualLines.Count);
newLines.RemoveRange(0, headEqualLines.Count);
minLineCount -= headEqualLines.Count;
var tailEqualLines = new List<string>();
if (oldLines.Count > 0 && newLines.Count > 0) {
for (var i = 1; i <= minLineCount; i++) {
if (VbaLineEqual(oldLines[oldLines.Count - i], newLines[newLines.Count - i])) {
tailEqualLines.Add(oldLines[oldLines.Count - i]);
} else {
break;
}
}
tailEqualLines.Reverse();
oldLines.RemoveRange(oldLines.Count - tailEqualLines.Count - 1, tailEqualLines.Count);
newLines.RemoveRange(newLines.Count - tailEqualLines.Count - 1, tailEqualLines.Count);
}
var lengths = new int[oldLines.Count + 1, newLines.Count + 1];
for (var i = 0; i < oldLines.Count; i++) {
for (var j = 0; j < newLines.Count; j++) {
if (VbaLineEqual(oldLines[i], newLines[j]))
lengths[i + 1, j + 1] = lengths[i, j] + 1;
else
lengths[i + 1, j + 1] = lengths[i + 1, j] > lengths[i, j + 1] ? lengths[i + 1, j] : lengths[i, j + 1];
}
}
var result = new List<string>();
var x = oldLines.Count;
var y = newLines.Count;
while (x != 0 && y != 0) {
if (lengths[x, y] == lengths[x - 1, y]) {
x--;
} else if (lengths[x, y] == lengths[x, y - 1]) {
result.Add(newLines[y - 1]);
y--;
} else {
result.Add(oldLines[x - 1]);
x--;
y--;
}
}
while (y != 0) {
result.Add(newLines[y - 1]);
y--;
}
result.Reverse();
return string.Join("\r\n", headEqualLines.Concat(result).Concat(tailEqualLines));
}
static bool VbaLineEqual(string oldLine, string newLine) {
if (string.Equals(oldLine, newLine, StringComparison.InvariantCulture))
return true;
if (!string.Equals(oldLine, newLine, StringComparison.InvariantCultureIgnoreCase))
return false;
var quoting = false;
for (var i = 0; i < oldLine.Length; i++) {
if (quoting && oldLine[i] != newLine[i])
return false;
if (oldLine[i] == '"')
quoting = !quoting;
}
return true;
}
但是当我针对一对5000行左右的字符串运行并且在开头和结尾附近进行更改时,性能和内存使用都非常可怕,可能是因为分配了5,000×5,000 int
的数组
是否有任何可以处理此比较的预构建库,或者我可以使用的更有效的算法?请注意,我想在zlib许可下许可我的代码,因此GNU diffutils并不好。