#rust
#Ржавчина
Вопрос:
Итак, в принципе, у меня есть текстовый файл со следующим синтаксисом:
String int
String int
String int
У меня есть идея, как прочитать значения, если в строке есть только одна запись, но если их несколько, я не знаю, как это сделать.
В Java я бы сделал что-то простое с while и Scanner, но в Rust я понятия не имею.
Я довольно новичок в Rust, поэтому, пожалуйста, помогите мне.
Заранее спасибо за помощь
Решение
Вот мое модифицированное решение кода @netwave:
use std::fs;
use std::io::{BufRead, BufReader, Error};
fn main() -> Result<(), Error> {
let buff_reader = BufReader::new(fs::File::open(file)?);
for line in buff_reader.lines() {
let parsed = sscanf::scanf!(line?, "{} {}", String, i32);
println!("{:?}n", parsed);
}
Ok(())
}
Комментарии:
1. Пахнет появлением кода 🙂
2. @Netwave да, вы правы 🙂
3. Смотрите
std::fs::File
иread_to_string
функцию, подходящую для чтения всего файла, или вы можете использоватьBuffReader
в ответе Netwave для чтения одной строки за раз
Ответ №1:
Вы можете использовать BuffRead
признак, у которого есть read_line
метод. Также вы можете использовать lines
.
Для этого самым простым вариантом было бы обернуть File
экземпляр с помощью BuffReader
:
use std::fs;
use std::io::{BufRead, BufReader};
...
let buff_reader = BufReader::new(fs::File::open(path)?);
loop {
let mut buff = String::new();
buff_reader.read_line(amp;mut buff)?;
println!("{}", buff);
}
std::io::Result {
let f = File::open(«log.txt»)?;
let mut reader = BufReader::new(f);
let mut line = String::new();
let len = reader.read_line(&mut line)?;
println!(«First line is {} bytes long», len);
Ok(())
}amp;edition=2018″ rel=»nofollow noreferrer»>Игровая площадка
Получив каждую строку, вы можете легко использовать sscanf
crate для разбора строки на нужные вам типы:
let parsed = sscanf::scanf!(buff, "{} {}", String, i32);
Комментарии:
1. Если вы предпочитаете написать свой собственный макрос для анализа данных вместо использования ящика, вот низкотехнологичная версия, которая по-прежнему довольно универсальна. (игровая площадка не поддерживает ввод-вывод, поэтому я просто дал ему литерал, но он все еще показывает его использование)
2. спасибо за этот простой фрагмент кода, я немного изменил его
Ответ №2:
На основе: https://doc.rust-lang.org/rust-by-example/std_misc/file/read_lines.html
Для data.txt
того, чтобы содержать:
str1 100
str2 200
str3 300
use std::fs::File;
use std::io::{self, BufRead};
use std::path::Path;
fn main() {
// File hosts must exist in current path before this produces output
if let Ok(lines) = read_lines("./data.txt") {
// Consumes the iterator, returns an (Optional) String
for line in lines {
if let Ok(data) = line {
let values: Vec<amp;str> = data.split(' ').collect();
match values.len() {
2 => {
let strdata = values[0].parse::<String>();
let intdata = values[1].parse::<i32>();
println!("Got: {:?} {:?}", strdata, intdata);
},
_ => panic!("Invalid input line {}", data),
};
}
}
}
}
// The output is wrapped in a Result to allow matching on errors
// Returns an Iterator to the Reader of the lines of the file.
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
where P: AsRef<Path>, {
let file = File::open(filename)?;
Ok(io::BufReader::new(file).lines())
}
Выводит:
Got: Ok("str1") Ok(100)
Got: Ok("str2") Ok(200)
Got: Ok("str3") Ok(300)
Комментарии:
1. Немного сложный, но правильный ответ
2. хороший момент! не для начинающих, ссылка на игровую площадку от Netwave хороша и проста!
3. Да, его ответ был сокращен с использованием таких вещей, как оператор try (
?
), что устраняет необходимость вif let
s иsscanf
кажется достаточно хорошим для выполнения синтаксического анализа.