让我们从头开始。我有字符串:
LOAD B
STORE $2
LOAD A
MPY =5.01E+10
ADD $2
以这种方式查看代码:
string code = "LOAD B\r\nSTORE $2\r\nLOAD A\r\nMPY =5.01E+10\r\nADD $2\r\n";
并以这种方式将其转换为LinkedListNode:
IEnumerable<KeyValuePair<string, string>> pairs =
code.Split(new string[] { Environment.NewLine },
StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Split(new[] { ' ' },
StringSplitOptions.RemoveEmptyEntries))
.Select(x => new KeyValuePair<string, string>(x[0], x[1]));
var data = new LinkedList<KeyValuePair<string, string>>(pairs);
此列表的元素是KeyValuePair,包含每行字符串的左右部分。现在是主要部分。我必须在此列表中找到序列"LOAD a => STORE b"
,其中a
和b
可以是任何字符串。在此之后,我必须在列表的下一部分找到包含key == b
的所有元素(在我的示例中为b = "$2"
)并将b
替换为a
,所以这里将是:
LOAD B
STORE B //changed
LOAD A
MPY =5.01E+10
ADD B //changed
所以,这是我的代码:
string a;
string b;
for(LinkedListNode<KeyValuePair<string, string>> it = data.First; it != null; it = it.Next) {
if(it.Next != null) {
if ((it.Value.Key == "LOAD") &&
(it.Next.Value.Key == "STORE")) {
a = it.Value.Value;
b = it.Next.Value.Value;
for(LinkedListNode<KeyValuePair<string, string>>
current = it; current != null;
current = current.Next) {
//remove found element and replace it
if (current.Value.Value == b) {
data.AddAfter(current, new KeyValuePair<string, string> (current.Value.Key, a));
data.Remove(current);
}
}
}
}
}
运行后我得到了这个:
LOAD B
STORE B //changed
LOAD A
MPY =5.01E+10
ADD $2 //still the same
我尝试对其进行调试并发现,if (current.Value.Value == b)
在某些情况下实际上并不匹配ADD $2
。什么可能是错的?
您可以通过以下方式查看列表中的内容:
foreach (KeyValuePair<string, string> pair in data) {
Console.WriteLine("Key: {0} - Value: {1}", pair.Key, pair.Value);
}
答案 0 :(得分:1)
我认为您的代码被破坏的原因是,当您从内部循环中的链接列表中删除current
时,Next
和Previous
的值为{{1}将get设置为null。因此,只要在列表中进行任何替换,内部循环中的迭代就会终止。在LinkedListNode<KeyValuePair<string, string>>
之后立即检查调试器中的这些值,看看我的意思。
在尝试修改数据时,我会使用稍微不同的模式。当我快速查看LinqPad中的解决方案时,我想出了这个:
data.Remove(current)
我没有修改现有的列表,而是创建了一个副本。我发现在不修改被迭代的数据结构的情况下,更容易阅读代码。另外,我认为这可以摆脱你的错误。
所以我开始使用“列表中的上一个节点是什么”的空值,并使用var newData = new LinkedList<KeyValuePair<string, string>>();
Nullable<KeyValuePair<string,string>> previousNode = null;
string valueToFind = "$2";
string valueToReplace = null;
foreach(var currentNode in data)
{
if(previousNode != null)
{
if(previousNode.Value.Key == "LOAD" && currentNode.Key == "STORE")
{
valueToReplace = previousNode.Value.Value;
}
}
if(valueToReplace != null && currentNode.Value == valueToFind)
{
var newValue = new KeyValuePair<string,string>(currentNode.Key, valueToReplace);
newData.AddLast(newValue);
}
else
{
newData.AddLast(currentNode);
}
previousNode = currentNode;
}
遍历整个列表。如果要查看上一个节点,则代码会检查它是否为“LOAD”且当前节点为“STORE”。如果是这样,它将“LOAD”操作的参数副本作为“要替换的值”。
然后,如果我们有一个要替换的值,并且当前节点的foreach()
等于我们需要找到的值(在您的示例中为“$ 2”),则代码会创建一个新的列表节点并进行替换。否则,它只是将当前节点按原样插入新列表中。
这为我提供了以下输出:
我认为你追求的是什么?
答案 1 :(得分:1)
终于找到了解决方案:
if (current.Value.Value == b) {
current.Value = new KeyValuePair<string, string> (current.Value.Key, a);
}
如果您需要替换list元素的值,您只需要:
LinkedListNode.Value = new value;