LINUX.ORG.RU

Чтение из UTF-8 файла в массив на языке Rust

 ,


0

5

Господа, имеется такой код:

use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;

fn main() {
    let args : Vec<String> = std::env::args().collect();
    if args.len() < 2 {
        println!("Wrong! Use: {} filename", args[0]);
        return;
    }
    
    let file_name = args[1].to_string();
    let input_file = match File::open(&file_name) {
        Ok(file) => file,
        Err(_) => {
            println!("File {} not found.", file_name);
            return;
        }
    };

    let mut reader = BufReader::new(input_file);

    let mut buf = [0u8; 512];
    loop {
        let length = reader.read(&mut buf).ok().unwrap();
        if length == 0 {
            break;
        }
        let _s = match std::str::from_utf8(&buf[0..length]) {
            Ok(string) => string,
            Err(e) => panic!("{}", e),
        };  
    }

}

Проблема в том, что в файлах вперемешку идут символы разной ширины (ASCII и кириллица), поэтому иногда в буфер знак целиком не влезает и я получаю что-то вроде:

thread '<main>' panicked at 'invalid utf-8: invalid byte near index 511'

Собственно вопрос: как эффективно разрулить эту ситуацию? Дочитывать по байту, пока декодирование не пройдёт успешно? Или использовать что-то ещё?

Решение такого типа:

let mut s = std::string::String::new();
    loop {
        let length = reader.read_to_string(&mut s).ok().unwrap();
        if length == 0 {
            break;
        }
    }
не подходит, файл может быть очень большой, нужно экономить память. То же самое касается и read_line.

★★★

Ответ на: комментарий от anonymous

Есть вариант написать проще?

есть вариант написать понятнее.

Аналогично? Если ты хотя бы понимаешь, что тут делается.

к сожалению, понимаю, лучше бы не понимал.

Вот тут уже сложней, но тут делается то, что ваш раст просто напросто не умеет. И даже не предусматривает.

язык rust действительно части из приведенного тобой говна не предусматривает, библиотеки для того чтобы делать аналогичные вещи - есть, в стандартной библиотеке есть не все.

Вот как ты, например, будешь сортировать массив строк в utf8. Сможешь показать?

v.sort();

а что, как-то сложнее должно быть?

maloi ★★★★★
()
Ответ на: комментарий от endeneu13

Ололо, и это ваш хваленый Rust? По читабельности с Perl может посоревноваться.

где ты в перле такое видел? это це-плюс-плюс.

waker ★★★★★
()
Ответ на: комментарий от tailgunner

На не-шутке.

Так я не pattern matching имел в виду, а код в общем. Взять первую же строку:

let mut reader = BufReader::new(input_file);

Против С++:

BufReader reader(input_file);

Где явно виден тип переменной и нет синтаксического мусора let,=,::,new. А если забивать на тип и полагаться на вывод типов, то лучше уж взять стиль JS:

reader = new BufReader(input_file);

Который даже на слух проговаривается - reader это новый BufReader, созданный для input_file.

Очень сомневаюсь, что писать на Rust сложнее, чем писать на Си. Впрочем... см выше.

А кто говорил про С? Код на С еще сложнее будет.

anonymous
()
Ответ на: комментарий от maloi

а что, как-то сложнее должно быть?

Ясно, начнешь писать что-то серьезное, чем будут пользоваться люди, - приходи.

anonymous
()
Ответ на: комментарий от anonymous

Это ML + С, но ты про такое, наверное, и не слышал.

Уточню на всякий случай - про ML.

anonymous
()
Ответ на: комментарий от anonymous

Перед тем как высказать свое мнение? Да.

голословненько. можешь привести пример на ml+C, который выглядит более похоже на приведенный расто-код, чем кресты?

waker ★★★★★
()
Ответ на: комментарий от maloi

Там же break. Я выхожу из цикла. Если бы length могло быть неинициализированным компилятор бы заругался, там всё проверенно.

Weres ★★★
() автор топика
Ответ на: комментарий от anonymous

«Писать, слова => если, так не! {} принято языке нормальном в как: то понять, (_) можно; проблем без let труднее но».

я не pattern matching имел в виду

Pattern matching ты точно имел в виду, хотя и перепутал порядок условия и действия.

BufReader reader(input_file);

Это объявление функции, да?

нет синтаксического мусора let,=,::,new

let не мусор, а маркер «сейчас будет имя переменной», new - просто функция.

А кто говорил про С?

Ты рассуждал о том, что мне легче трепаться, чем писать на Rust - так вот, я пишу на Си.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Это объявление функции, да?

Это выводиться из контекста. Контекстное мышление это особенность мышления человеческого. Хотя какое мышления у адептов руста.

На этом строится любой язык, в том числе понятие переменной. Либо перед каждой переменной у тебя стоит let, а перед каждой фнукцией fn?

let x = let y; fn f(fn b, fn c);

let не мусор, а маркер «сейчас будет имя переменной», new - просто функция.

Мусор. А ну ок, так и будут. Сейчас_будет_имя тайлингер - сейчас_будет_определение балабол, как_назвать_это пишущий как_назвать_это на сейчас_будет_имя си сейчас_будет_число 89 как_назвать_это как как_назвать_это + сейчас_будет_число пятилетка.

Ахриненный язык.

Ты рассуждал о том, что мне легче трепаться, чем писать на Rust - так вот, я пишу на Си.

Это очень громкое заявление.

TrueTsar1C
()
Ответ на: комментарий от tailgunner

Так что pattern matching ты точно имел в виду, хотя и перепутал порядок условия и действия.

Не имел. Вставил просто так.

Это объявление функции, да?

Прототип. Да, был бы, если б input_file был типом, а само объявление было бы вынесено из функции. Кстати в С++11 специально добавили:

BufReader reader{input_file};

Но мне и старый стиль не мешает, ни разу не путал одно с другим.

let не мусор, а маркер «сейчас будет имя переменной», new - просто функция.

А на питоне ты пишешь, например?

reader = BufReader()

Вот такое вот волшебство, оказывается не нужен ни let, ни new.

Ты рассуждал о том, что мне легче трепаться, чем писать на Rust - так вот, я пишу на Си.

Мои соболезнования (с).

anonymous
()
Ответ на: комментарий от anonymous

Так что pattern matching ты точно имел в виду, хотя и перепутал порядок условия и действия.

Не имел. Вставил просто так.

Ну окей.

Ты рассуждал о том, что мне легче трепаться, чем писать на Rust - так вот, я пишу на Си.

Мои соболезнования (с).

Самому себя жалко :/

tailgunner ★★★★★
()
Ответ на: комментарий от TrueTsar1C

Мнение подделки под безумного ПТУшника очень важно для нас всех.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от maloi

По хорошему, consume стоило бы вызывать в ветке Ok, но в той области видимости существует результат вызова fill_buf и компилятор не даёт вызвать второй метод трейта, меняющий внутреннее состояние.

Weres ★★★
() автор топика
Ответ на: комментарий от anonymous

Добавить codecvt_utf8, легко, просто, удобно.

Да нефига не просто и не удобно. Никто стримы плюсовые особо не хвалит.

DarkEld3r ★★★★★
()
Ответ на: комментарий от anonymous

А если забивать на тип и полагаться на вывод типов, то лучше уж взять стиль JS:

Вообще-то тут тип точно так же явно виден.

DarkEld3r ★★★★★
()
Ответ на: комментарий от DarkEld3r

Да нефига не просто и не удобно. Никто стримы плюсовые особо не хвалит.

Их не хвалят, т.к. обычно их используют для форматированного ввода/вывода. А там они действительно многословны, медленны (относительно) и вообще не фонтан. Если же их использовать просто для чтения/записи, в том числе текста, то они и просты и удобны.

anonymous
()
Ответ на: комментарий от DarkEld3r

Вообще-то тут тип точно так же явно виден.

Это ровно то, за что ругают перегрузку операторов. Оно же типа явно видно, что должно получится. Ну все логично же. А на деле какой-нибудь ::new может тебе вернуть совсем не то, что ты интуитивно ожидаешь. И компилятор в данном случае явно попросили не вмешиваться и ничего не проверять.

anonymous
()
Ответ на: комментарий от anonymous

А на деле какой-нибудь ::new может тебе вернуть совсем не то, что ты интуитивно ожидаешь.

Лично у меня с этим никогда проблем не было. Но если на то пошло, то раст как раз «очевиднее» плюсов - перегрузки функций-то нет. Как и исключений. Только не уверен, что это плюс.

DarkEld3r ★★★★★
()
Ответ на: комментарий от greatchina

Есть два класса языков: те, которые ругают и те, на которых никто не пишет.

И rust относится к обоим.

anonymous
()
Ответ на: комментарий от DarkEld3r

перегрузки функций-то нет

Есть - через трейты. И к ::new это тоже относится. Ну еще и макросы, которые приходится использовать там, где в С++ есть перегрузка функций, а трейты не катят.

anonymous
()
Ответ на: комментарий от anonymous

Есть - через трейты.

Я в курсе. Но «неявного» поведения в С++, в любом случае, больше. Но повторюсь - я не считаю это проблемой, скорее наоборот.

Ну еще и макросы, которые приходится использовать там, где в С++ есть перегрузка функций, а трейты не катят.

В С++ на макросах тоже много чего можно натворить.

DarkEld3r ★★★★★
()
Ответ на: комментарий от DarkEld3r

Я в курсе.

Ну вот. При том язык поощряет неуказание типа переменной. Взять код servo - сплошное let mut v =... И это понятно, никто не хочет писать лапшу, которая получится при полном описании. В итоге страдает качество кода. Ты где-то поменял тип результат функции с u32 на u8, и, внезапно, сломал ранее рабочий код совсем в другом месте из-за integer overflow.

Но «неявного» поведения в С++, в любом случае, больше. Но повторюсь - я не считаю это проблемой, скорее наоборот.
В С++ на макросах тоже много чего можно натворить.

Это отдельная, уже давно избитая, тема

anonymous
()
Ответ на: комментарий от anonymous

Ты где-то поменял тип результат функции с u32 на u8, и, внезапно, сломал ранее рабочий код совсем в другом месте из-за integer overflow.

Поломал компиляцию, скорее всего. И почему эта проблема специфична для Rust?

tailgunner ★★★★★
()
Ответ на: комментарий от anonymous

При том язык поощряет неуказание типа переменной.

Вообще-то сейчас как раз модно тип не указывать. И чем С++ в этом плане лучше? Точно так же можно везде auto пихать и многие так и делают. В каком-нибудь шарпе аналогично.

Ты где-то поменял тип результат функции с u32 на u8

В расте нeт неявного приведения числовых типов. А вот в С++ как раз оно легко приводится, разве что ворнинг быть может.

DarkEld3r ★★★★★
()
Ответ на: комментарий от tailgunner

Поломал компиляцию, скорее всего.

fn foo() -> u8 { 100 }

// This code is editable and runnable!
fn main() {
    // A simple integer calculator:
    // `+` or `-` means add or subtract by 1
    // `*` or `/` means multiply or divide by 2

    let program = "+ + * - /";
    let mut accumulator = foo();

    for token in program.chars() {
        match token {
            '+' => accumulator *= 100,
            '-' => accumulator *= 100,
            '*' => accumulator *= 100,
            '/' => accumulator *= 100,
            _ => { /* ignore everything else */ }
        }
    }

    println!("The program \"{}\" calculates the value {}",
              program, accumulator);
}

The program «+ + * - /» calculates the value 0

И почему эта проблема специфична для Rust?

Ты сам назвал ее проблемой. Она не специфична, но в питоне, например, ее нет.

anonymous
()
Ответ на: комментарий от DarkEld3r

Вообще-то сейчас как раз модно тип не указывать. И чем С++ в этом плане лучше? Точно так же можно везде auto пихать и многие так и делают. В каком-нибудь шарпе аналогично.

Не видел, чтоб в С++ кто-то вместо int32_t, например, писал auto. В этом просто нет смысла. Обычно auto используют для итераторов. В rust же смысл есть - сэкономить на коде можно всегда.

В расте нeт неявного приведения числовых типов.

Я выше привел пример, раст съел и не подавился.

anonymous
()
Ответ на: комментарий от anonymous

совсем в другом месте из-за integer overflow

Подумаешь... Такая мелочь детектится и фиксится... А вот когда выводится совсем другой *полиморфный* тип — вот это действительно страшно.

Что хотели, то и получили. В хаскеле, например, такая ситуация перманентна, и всякие-разные пакетики и расширения GHC только набрасывают говн на вентиляторы. И ничё, живём.

Растовцам придётся осваивать определенную дисциплину и гигиену, или не пользоваться.

Macil ★★★★★
()
Ответ на: комментарий от anonymous

The program «+ + * - /» calculates the value 0

В debug «thread '<main>' panicked at 'arithmetic operation overflowed'».

И почему эта проблема специфична для Rust?

Ты сам назвал ее проблемой

То есть это не проблема? Ну окей.

tailgunner ★★★★★
()
Ответ на: комментарий от Macil

А вот когда выводится совсем другой *полиморфный* тип — вот это действительно страшно.

Глобального вывода типов проблемы.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

В debug «thread '<main>' panicked at 'arithmetic operation overflowed'».

Ну ты ж не ребенок, понимаешь, что реальные данные, на которых программа молча сфейлится, подсунут уже в релизе. А у тебя на твоих данных будет, например, 10*10 и УМВР.

То есть это не проблема? Ну окей.

Ты путаешься в показаниях.

anonymous
()
Ответ на: комментарий от tailgunner

Глобального вывода типов проблемы.

Не. Общефилософская проблема: чем более обще, тем больше теряется конкретики и наоборот.

Более узкая проблема — денотационная семантика ничего не знает о вычислительной эффективности/сложности. Т.е. не все моноиды одинаково полезны ;)

Ещё более узкая проблема — лулзы с левыми и правыми свёртками.

Но ведь создатели Раста именно *этого* и хотели, правда?

Macil ★★★★★
()
Ответ на: комментарий от unt1tled

а зачем в этом вашем русте нужно fn и let?

Их авторы раста просто скопровали из ML, где точно такие же fun и let.а

anonymous
()
Ответ на: комментарий от anonymous

Не видел, чтоб в С++ кто-то вместо int32_t, например, писал auto.

Ну я видел. Более того, сталкивался и с соглашениями о коде, когда если мы используем тип возвращаемый функцией, то авто требуется/рекомендуется.

Я выше привел пример, раст съел и не подавился.

Ну там приведения и нет, но согласен - это может быть проблемой. Вот только раст тут никак хуже не сделал. Если ты подумал о типе для аккумулятора, то можешь точно так же его явно указать.

От всех ошибок раст (как и любой язык), понятное дело, не спасёт. Тесты никогда не помешают.

DarkEld3r ★★★★★
()
Ответ на: комментарий от DarkEld3r

Ну я видел.

Оторви им руки и не пришивай назад.

Если ты подумал о типе для аккумулятора, то можешь точно так же его явно указать.

Если взять тот же servo, там в общем и целом клали на всякие там типы для переменных. И наверняка это будет актуально для типичного кода на rust.

anonymous
()
Ответ на: комментарий от anonymous

И почему эта проблема специфична для Rust?

Ты сам назвал ее проблемой

То есть это не проблема? Ну окей.

Ты путаешься в показаниях.

Не-а. Это просто ты строишь из себя загадочного мудреца.

tailgunner ★★★★★
()
Ответ на: комментарий от Macil

Но ведь создатели Раста именно *этого* и хотели, правда?

Нет.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Не-а. Это просто ты строишь из себя загадочного мудреца.

Я думал, что мы вместе сошлись на том, что это проблема, а ты вдруг решил включить заднюю.

anonymous
()
Ответ на: комментарий от anonymous

Если взять тот же servo, там в общем и целом клали на всякие там типы для переменных.

Повторюсь - сейчас «почти везде» рекомендуют не указывать тип. Мол более важно то, что мы делаем, а не с каким именно типом. Ты всё-таки привёл слишком искусственный код, я бы не стал из этого делать вывод о наличии проблем.

DarkEld3r ★★★★★
()
Ответ на: комментарий от DarkEld3r

Повторюсь - сейчас «почти везде» рекомендуют не указывать тип.

«Почти везде» решают немного другие задачи или язык сам тебя подстраховывает.

Ты всё-таки привёл слишком искусственный код, я бы не стал из этого делать вывод о наличии проблем.

Вообще-то rust это ж замена С и С++, не? А значит «байто%бство» с теми самыми u8, i16 etc. это его прямое предназначение. В отличие от того самого «почти везде».

anonymous
()
Ответ на: комментарий от anonymous

«Почти везде» решают немного другие задачи

Раст, в общем-то, «язык общего назначения», как и большинство мейнстримовых языков.

или язык сам тебя подстраховывает.

Как?

А значит «байто%бство» с теми самыми u8, i16 etc. это его прямое предназначение.

И как из этого следует необходимость инициализировать аккумулятор вызовом какой-то левой функции? Ну или обобщая - зачем отключать голову при написании кода? Да, раст не спасёт от всех проблем. Но разве кто-то это обещал?

DarkEld3r ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.