替换 List<string> 中特定索引处的字符,但索引器是只读的

Replace character at specific index in List<string>, but indexer is read only

这是一个基本问题,但我是用 C++ 学习编程的,现在正过渡到 C#,所以我对 C# 方法的无知妨碍了我。

一位客户给了我一些固定长度的文件,他们想要每条奇数记录的第 484 个字符,跳过第一个(3、5、7 等...)从 space 到 0。在我看来,我应该能够执行如下操作:

static void Main(string[] args)
{
    List<string> allLines = System.IO.File.ReadAllLines(@"C:\...").ToList();

    foreach(string line in allLines)
    {
        //odd numbered logic here
        line[483] = '0';
    }
...
//write to new file
}

但是,属性 或索引器无法分配给它,因为它是只读的。我所有的阅读都说我没有为变量设置 setter,并且我已经尝试了 this SO article 处显示的内容,但我每次都做错了。该文章中显示的内容应该有效吗?我应该做点别的吗?

foreach 之后的第一项(在本例中为字符串行)是一个局部变量,它在循环之外没有作用域 - 这就是为什么不能为其赋值的原因。尝试改用常规的 for 循环。

您不能直接修改 C# 字符串,因为它们是不可变的。您可以将字符串转换为 char[],修改它,然后再次制作一个 string,并将其写入文件:

File.WriteAllLines(
    @"c:\newfile.txt"
,   File.ReadAllLines(@"C:\...").Select((s, index) => {
        if (index % 2 = 0) {
            return s; // Even strings do not change
        }
        var chars = s.ToCharArray();
        chars[483] = '0';
        return new string(chars);
    })
);

for each 的目的是遍历容器。它本质上是只读的。您应该使用常规的 for 循环。它会起作用。

 static void Main(string[] args)
    {
        List<string> allLines = System.IO.File.ReadAllLines(@"C:\...").ToList();

        for (int i=0;i<=allLines.Length;++i)
        {
           if (allLines[i].Length > 483)
    {
        allLines[i] = allLines[i].Substring(0, 483) + "0";
    }
        }
    ...
    //write to new file
    }

由于字符串是不可变的,您不能通过将其视为 char[] 来修改单个字符,然后修改特定索引处的字符。但是,您 可以 "modify" 通过将其分配给新字符串来实现。

我们可以使用Substring()方法来return原始字符串的任何部分。将此与一些连接相结合,我们可以获取字符串的第一部分(直到要替换的字符),添加新字符,然后添加原始字符串的其余部分。

此外,由于我们无法直接修改在 foreach 循环中迭代的集合中的项目,我们可以将您的循环切换为 for 循环。现在我们可以通过索引访问每一行,并且可以动态修改它们:

for(int i = 0; i < allLines.Length; i++)
{
    if (allLines[i].Length > 483)
    {
        allLines[i] = allLines[i].Substring(0, 483) + "0" + allLines[i].Substring(484);
    }
}

有可能,根据您正在处理的行数以及最终进行的内联串联的数量,使用 StringBuilder 代替串联可能会表现得更好。这是使用 StringBuilder 执行此操作的另一种方法。我会把性能测量留给你...

var sb = new StringBuilder();
for (int i = 0; i < allLines.Length; i++)
{
    if (allLines[i].Length > 483)
    {
        sb.Clear();
        sb.Append(allLines[i].Substring(0, 483));
        sb.Append("0");
        sb.Append(allLines[i].Substring(484));

        allLines[i] = sb.ToString();
    }
}