2014-10-23 6 views
7

Я пишу на STDIN строку чисел (например, «4 10 30 232312»), и я хочу ее прочитать и преобразовать в массив из int (или вектор) в ржавчине, не может найти правильный путь, до сих пор у меня есть:Преобразование строки чисел в массив/вектор int в Rust

use std::io; 

fn main() { 
    let mut reader = io::stdin(); 
    let numbers = reader.read_line().unwrap(); 
} 

Спасибо заранее

ответ

8

На Rust 1.5.x, рабочий раствор:

fn main() {  
    let mut numbers = String::new(); 

    io::stdin().read_line(&mut numbers).ok().expect("read error"); 

    let numbers: Vec<i32> = numbers 
     .split_whitespace() 
     .map(|s| s.parse().unwrap()) 
     .collect(); 

    for num in numbers { 
     println!("{}", num); 
    } 
} 
12

Обновлено для Rust 1.x

Вы можете сделать что-то вроде этого:

use std::io::{self, BufRead};     // (a) 

fn main() { 
    let reader = io::stdin(); 
    let numbers: Vec<i32> = 
     reader.lock()       // (0) 
       .lines().next().unwrap().unwrap() // (1) 
       .split(' ').map(|s| s.trim())  // (2) 
       .filter(|s| !s.is_empty())  // (3) 
       .map(|s| s.parse().unwrap())  // (4) 
       .collect();      // (5) 
    println!("{:?}", numbers); 
} 

Сначала мы берем блокировку stdin, которая позволяет работать с stdin в качестве буферизованного считывателя (по умолчанию stdin в Rust не загружается; вам нужно вызвать метод lock(), чтобы получить его буферизованную версию, но эта буферизованная версия предназначена только для всех потоков в вашей программе, поэтому доступ к ней должен быть синхронизирован).

Далее мы читаем следующую строку (1); Я использую lines() итератор, метод next() возвращает Option<io::Result<String>>, поэтому для получения всего String вам нужно unwrap() дважды.

Затем мы разделим его на пробелы и обрезаем результирующие куски из дополнительных пробелов (2), удалим пустые куски, оставшиеся после обрезки (3), преобразуем строки в i32 s (4) и соберите результат с вектором (5).

Для использования метода нам также необходимо импортировать std::io::BufRead признак (a).

Если вы заранее знаете, что ваш вход не будет содержать более чем один пробел между числами, вы можете пропустить шаг (3) и переместить trim() вызова из (2) в (1):

let numbers: Vec<i32> = 
    reader.lock() 
      .lines().next().unwrap().unwrap() 
      .trim().split(' ') 
      .map(|s| s.parse().unwrap()) 
      .collect(); 

Обновление

ржавчины, однако, уже предоставляет способ для разбиения строки в последовательность пробельных разделенных слов, называется split_whitespace():

let numbers: Vec<i32> = 
    reader.read_line().unwrap().as_slice() 
     .split_whitespace() 
     .map(|s| s.parse().unwrap()) 
     .collect() 

split_whitespace() фактически представляет собой комбинацию split() и filter(), как и в моем оригинальном примере. Он использует функцию в аргументе split(), хотя он проверяет разные типы пробелов, а не только символы пробела. Вы можете найти его источник: here.

+0

Спасибо, Владимир, ты спас день. На стороне примечания, ничего себе, Ржавчина действительно интенсивна! –

+1

Существует также способ использовать регулярные выражения для разделения произвольными пробелами. Вероятно, это даст код terser, но для этого требуется использование нестандартных ящиков (хотя он включен в дистрибутив). Пример [здесь] (http://doc.rust-lang.org/regex/enum.Regex.html#method.split) - это почти то, что вы хотите. –

+4

Вы также можете использовать ['.words()'] (http://doc.rust-lang.org/nightly/std/str/trait.UnicodeStrSlice.html#tymethod.words) (немного более общий, чем просто пробелы , хоть). – huon

1

Более безопасный вариант. Этот пропустить неудачные разборки, так что неудачный разворот не паникует. Используйте read_line для чтения одной строки.

let mut buf = String::new(); 

// use read_line for reading single line 
std::io::stdin().read_to_string(&mut buf).expect(""); 

// this one skips failed parses so that failed unwrap doesn't panic 
let v: Vec<i32> = buf.split_whitespace().filter_map(|w| w.parse().ok()).collect(); 

Вы даже можете прочитать Vector of Vectors, как это.

let stdin = io::stdin(); 
let locked = stdin.lock(); 
let vv: Vec<Vec<i32>> = locked.lines() 
    .filter_map(
     |l| l.ok().map(
      |s| s.split_whitespace() 
       .filter_map(|word| word.parse().ok()) 
       .collect())) 
    .collect(); 

Над одним работает для входов, как

2 424 -42 124 
42 242 23 22 241 
24 12 3 232 445 

затем превращает их в его

[[2, 424, -42, 124], 
[42, 242, 23, 22, 241], 
[24, 12, 3, 232, 445]] 

filter_map принимает замыкание, которое возвращает Option<T> и отфильтровывает все None с.

ok() превращает Result<R,E> в Option<R>, чтобы в этом случае можно было отфильтровывать ошибки.

Смежные вопросы