Проблема с 3D-массивом символов в D

89
8

Я изучаю 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., ]

Любая идея, что я делаю неправильно?

спросил(а) 2021-01-19T19:57:35+03:00 6 месяцев, 1 неделя назад
1
Решение
133

Основная проблема заключается в том, что 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);
}
}

ответил(а) 2021-01-19T19:57:35+03:00 6 месяцев, 1 неделя назад
110

Ответ на этот вопрос двоякий.


Во-первых, byLine, как указано, использует внутренний буфер (для скорости), который перезаписывается при последующих итерациях цикла.


Во-вторых, посмотрите на операции для words. split(strip(line)). strip только изменяет начало и конец массива (который является ссылкой), а разбиение разбивает массив на более мелкие подмассивы, которые ссылаются на одни и те же базовые данные. Не являются разрушительными; таким образом, не нужно перераспределять. Из-за этого окончательный string[] words по-прежнему указывает на исходный буфер, который перезаписывается на следующей итерации.

Решение состоит в том, чтобы убедиться, что вы скопируете данные, если хотите, чтобы он избежал области цикла, написав auto words = split(strip(line).dup);. Обратите внимание, что дублирование words не будет работать, так как это приведет к дублированию массива массивов, а не к массивам.


Кроме того, вы должны использовать string[] args. Синтаксис C-типа поддерживается только по устаревшим причинам и не рекомендуется для использования.

ответил(а) 2021-01-19T19:57:35+03:00 6 месяцев, 1 неделя назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема