我想知道是否有办法避免以下代码中的foreach
循环:
List<string> lines1 = new List<string>();
List<string> lines2 = new List<string>();
lines1.AddRange(File.ReadAllLines("in.txt"));
foreach(string s in lines1)
lines2.Add(Regex.Replace(s,"bim(.*)","bom$1");
请注意,循环还需要在处理期间有两个列表。我的目标是将一个正则表达式应用于列表 in situ 中的每个字符串。
答案 0 :(得分:6)
你say你不想迭代。然后不要创建一个开头的集合,而是用一个字符串读取整个文件:
string input = File.ReadAllText("in.txt");
string output = Regex.Replace(input, "bim(.*)", "bom$1");
然后,如果您想获得输入中的“行”,请按照Easiest way to split a string on newlines in .NET?中的说明拆分输出:
string[] outputLines = input.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
答案 1 :(得分:4)
您无法使用foreach
执行此操作,因为在迭代时无法修改集合,但您可以使用for
:
List<string> lines = new List<string>(File.ReadAllLines("in.txt"));
for(int i = 0; i < lines.Count; i++)
lines[i] = Regex.Replace(lines[i],"bim(.*)","bom$1");
或者单行:
List<string> lines = File.ReadLines("in.txt")
.Select(s => Regex.Replace(s ,"bim(.*)","bom$1"))
.ToList();
请注意,ReadLines
不会将整个文件读入内存,因此投影将在从文件中读取时转换行(意味着不会创建第二个集合)。
答案 2 :(得分:3)
只需使用常规for
循环即可避免需要额外的列表
for (var i=0; i<lines1.Count; i++)
{
lines1[i] = Regex.Replace(lines1[i],"bim(.*)","bom$1");
}
但请注意, 仍在为lines1
中的每个字符串创建一个新字符串,因为字符串是不可变的。
或者,如果你愿意,你可以写一个扩展方法,这样的东西应该可以工作:
public static class Extensions
{
public static IEnumerable<string> RegexReplace (this IEnumerable<string> strings, Regex regex, string replacement)
{
foreach (var s in strings)
{
yield return regex.Replace(s, replacement);
}
}
}
你可以这样称呼它:
var lines1 = File.ReadLines("in.txt").RegexReplace("bim(.*)","bom$1");
此扩展允许您将正则表达式应用于集合中的每个字符串,并且因为它使用延迟执行,所以在迭代之前它实际上不会执行任何操作。因此,例如,如果您只需要检查第一行(可能决定是否应该处理文件的其余部分),您就可以在不查看其余行的情况下快捷方式。在这种情况下,我们可以O(1)
获得最佳案例。