我正在学习D,我有一个简单的程序,它逐行读入文本文件,将每一行分成不同的单词,然后将整个内容打印到stdout。
import std.stdio;
import std.string;
void main(string args[])
{
char[][][] lines;
auto input = File(args[1], "r");
foreach(line; input.byLine())
{
auto words = split(strip(line));
lines ~= words;
}
foreach(line; lines)
{
writeln(line);
}
}
创建words
的代码有效。如果我每次分配单词时都会调用writeln
,我会得到我想要的输出。但是,如果我将words
添加到lines
并输出lines
,那么就会发生奇怪的事情。 lines
在源文件中的每一行都有一个条目,但每行都是最后一行读取的损坏版本。例如,如果文件的最后一行如下所示:
END START * End of routine
我得到的输出看起来像这样:
[ , END, ST, *, End , f rout, ne, , , e other]
[ , END, ST, *, End of, rout, ne, , , e othe]
[ , END, STAR, *, End of, rout, ne.,
e]
[ , END, START , *, End of, rout, ne.,
e]
[END , STAR]
[ , END, START , *, End , f , out, ne. ]
[END, START, *, End, of ro, tine. , , ,
]
[END, STA, *, o, r, ut]
[ , END , S, *, End, o, r, utine., , , ,
, o]
[END, START , *, of routi, e., ]
知道我做错了吗?
答案 0 :(得分:8)
你的主要问题是byLine正在使用相同的缓冲区,你需要复制它以便它不会覆盖你的数据
auto words = split(strip(line).dup);
更合适的存储类是字符串而不是char [],除非您打算修改实际字符。但是,您将在v 2.0中遇到编译器错误,因为 line 将是char []。这只是将其复制为不可变字符串的问题。
auto words = split(strip(line).idup);
这样你的程序就像
import std.stdio;
import std.string;
void main(string[] args)
{
string[][] lines;
auto input = File(args[1], "r");
foreach(line; input.byLine())
{
auto words = split(strip(line).idup);
lines ~= words;
}
foreach(line; lines)
{
writeln(line);
}
}
答案 1 :(得分:5)
答案是双重的。
首先,byLine
如上所述使用内部缓冲区(用于速度),在后续循环迭代中会被覆盖。
其次,查看words
的操作。 split(strip(line))
。 strip
仅修改数组(它是一个引用)的开始和结束,并且split将数组拆分为引用相同底层数据的较小子数组。也不是破坏性的;因此,既不需要重新分配。因此,最终string[] words
仍然指向原始缓冲区,在下一次迭代时会被覆盖。
解决方案是通过编写auto words = split(strip(line).dup);
来确保复制数据(如果您希望它转义循环范围)。请注意,执行words
将不工作,因为这只会复制数组数组,而不是数组本身。
此外,您应该使用string[] args
。仅支持类似C语法的遗留原因,不建议使用。