Проблема с 3D-массивом символов в D
Я изучаю 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., ]
Любая идея, что я делаю неправильно?
Основная проблема заключается в том, что byLine использует один и тот же буфер, вам необходимо его дублировать, чтобы он не переопределял ваши данные.
auto words = split(strip(line).dup);
Более подходящим классом хранения является строка вместо char [], если вы не собираетесь изменять действительные символы. Однако вы получите ошибку компилятора в версии 2.0, потому что строка будет 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);
}
}
Ответ на этот вопрос двоякий.
Во-первых, byLine
, как указано, использует внутренний буфер (для скорости), который перезаписывается при последующих итерациях цикла.
Во-вторых, посмотрите на операции для words
. split(strip(line))
. strip
только изменяет начало и конец массива (который является ссылкой), а разбиение разбивает массив на более мелкие подмассивы, которые ссылаются на одни и те же базовые данные. Не являются разрушительными; таким образом, не нужно перераспределять. Из-за этого окончательный string[] words
по-прежнему указывает на исходный буфер, который перезаписывается на следующей итерации.
Решение состоит в том, чтобы убедиться, что вы скопируете данные, если хотите, чтобы он избежал области цикла, написав auto words = split(strip(line).dup);
. Обратите внимание, что дублирование words
не будет работать, так как это приведет к дублированию массива массивов, а не к массивам.
Кроме того, вы должны использовать string[] args
. Синтаксис C-типа поддерживается только по устаревшим причинам и не рекомендуется для использования.