tag multiple ejemplos bootstrap input io rust

multiple - jquery tags input autocomplete



Cómo leer la entrada del usuario en Rust? (8)

Nota del editor: esta pregunta se refiere a partes de Rust que son anteriores a Rust 1.0, pero el concepto general sigue siendo válido en Rust 1.0.

Tengo la intención de hacer un tokenizer. Necesito leer cada línea que escribe el usuario y dejar de leer una vez que el usuario presiona ctrl - D.

Busqué alrededor y solo encontré un ejemplo en Rust IO que ni siquiera compila. Miré la documentación del módulo io y encontré que la función read_line() es parte de la interfaz ReaderUtil , pero stdin() devuelve un Reader .

El código que me gustaría sería esencialmente el siguiente en C ++

vector<string> readLines () { vector<string> allLines; string line; while (cin >> line) { allLines.push_back(line); } return allLines; }


Nota del editor: esta respuesta es anterior a Rust 1.0. Por favor vea las otras respuestas para soluciones modernas.

En Rust 0.4, use el rasgo de ReaderUtil para acceder a la función read_line . Tenga en cuenta que debe convertir explícitamente el valor en un tipo de rasgo, por ejemplo, el reader as io::ReaderUtil

fn main() { let mut allLines = ~[]; let reader = io::stdin(); while !reader.eof() { allLines.push((reader as io::ReaderUtil).read_line()); } for allLines.each |line| { io::println(fmt!("%s", *line)); } }


Nota del editor: esta respuesta es anterior a Rust 1.0. Por favor vea las otras respuestas para soluciones modernas.

Uh ... Después de muchas pruebas y errores, encontré una solución.

Todavía me gustaría ver una solución mejor, así que no voy a aceptar mi propia solución.

El siguiente código imprime exactamente lo que el usuario ingresa.

mod tokenizer { pub fn read () -> ~[int] { let reader = io::stdin(); let mut bytes: ~[int] = ~[]; loop { let byte: int = reader.read_byte(); if byte < 0 { return bytes; } bytes += [byte]; } } } fn main () { let bytes: ~[int] = tokenizer::read(); for bytes.each |byte| { io::print(#fmt("%c", *byte as char)); } }


A partir del 17 de abril de 2015 de mdcox en mozilla rust irc.

use std::io; fn main() { let mut stdin = io::stdin(); let input = &mut String::new(); loop { input.clear(); stdin.read_line(input); println!("{}", input); } }


En Rust 1.0 y posterior, puede usar el método de lines en cualquier elemento que implemente el rasgo std::io::BufRead para obtener un iterador sobre líneas en la entrada. También podría usar read_line , pero es más probable que usar el iterador sea lo que quiera. Aquí hay una versión de la función en la pregunta usando iteradores; vea abajo para una explicación más detallada. ( enlace de juegos )

use std::io; use std::io::prelude::*; pub fn read_lines() -> Vec<String> { let stdin = io::stdin(); let stdin_lock = stdin.lock(); let vec = stdin_lock.lines().filter_map(|l| l.ok()).collect(); vec }

Y aquí hay una versión que se parece más a la versión en C ++ de la pregunta, pero no es realmente la manera idiomática de hacer esto en Rust ( playground ):

use std::io; use std::io::prelude::*; pub fn read_lines() -> Vec<String> { let mut vec = Vec::new(); let mut string = String::new(); let stdin = io::stdin(); let mut stdin_lock = stdin.lock(); while let Ok(len) = stdin_lock.read_line(&mut string) { if len > 0 { vec.push(string); string = String::new(); } else { break } } vec }

Para obtener algo que implemente BufRead , que se necesita para llamar a lines() o read_line() , llame a std::io::stdin() para obtener un identificador para la entrada estándar, y luego llame a lock() sobre el resultado de eso para obtener el control exclusivo del flujo de entrada estándar (debe tener control exclusivo para obtener un BufRead , porque de lo contrario el almacenamiento en búfer podría producir resultados arbitrarios si dos hilos estuvieran leyendo de stdin a la vez).

Para recopilar el resultado en un Vec<String> , puede usar el método de collect en un iterador. lines() devuelve un iterador sobre Result<String> , por lo que debemos gestionar casos de error en los que no se pudo leer una línea; para este ejemplo, simplemente ignoramos los errores con un filter_map que simplemente omite cualquier error.

La versión similar a C ++ utiliza read_line , que agrega la línea de lectura a una cadena dada, y luego empujamos la cadena en nuestro Vec . Debido a que transferimos la propiedad de la cadena al Vec cuando lo hacemos, y debido a que read_line continuaría añadiendo a la string , tenemos que asignar una nueva cadena para cada ciclo (esto parece ser un error en la versión original de C ++ en el pregunta, en la que se comparte la misma cadena y así seguirá acumulando cada línea). Usamos while let continuar leyendo hasta que alcanzamos un error, y nos rompemos si leemos cero bytes que indica el final de la entrada.


Esto es lo que se me ocurrió (con la ayuda de gente amable del canal de IRC #rust en irc.mozilla.org):

use core::io::ReaderUtil; fn read_lines() -> ~[~str] { let mut all_lines = ~[]; for io::stdin().each_line |line| { // each_line provides us with borrowed pointers, but we want to put // them in our vector, so we need to *own* the lines all_lines.push(line.to_owned()); } all_lines } fn main() { let all_lines = read_lines(); for all_lines.eachi |i, &line| { io::println(fmt!("Line #%u: %s", i + 1, line)); } }

Y prueba de que funciona :)

$ rustc readlines.rs $ echo -en ''this/nis/na/ntest'' | ./readlines Line #1: this Line #2: is Line #3: a Line #4: test


Hay pocas maneras en que puedo pensar.

Lee toda la entrada en una sola String

let mut input = String::new(); io::stdin().read_to_end(&mut input);

Leer líneas en Vector . Éste no entra en panic cuando lee una línea falla, sino que omite esa línea fallida.

let stdin = io::stdin(); let locked = stdin.lock(); let v: Vec<String> = locked.lines().filter_map(|line| line.ok()).collect();

Además, si quieres analizarlo:

Después de leerlo en una cuerda haz esto. Puede analizarlo en otras colecciones que implementa FromIterator . Los elementos contenidos en la colección también deben implementar FromStr . Siempre que la restricción de rasgo satisfaga, puede cambiar Vec a cualquier Collection:FromIterator , Collection<T: FromStr>

let v: Vec<i32> = "4 -42 232".split_whitespace().filter_map(|w| w.parse().ok()).collect();

También puedes usarlo en StdinLock

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();


La pregunta es leer líneas de stdin y devolver un vector. En Rust 1.7:

fn readlines() -> Vec<String> { use std::io::prelude::*; let stdin = std::io::stdin(); let v = stdin.lock().lines().map(|x| x.unwrap()).collect(); v }


Rust 1.x (ver documentation ):

use std::io; use std::io::prelude::*; fn main() { let stdin = io::stdin(); for line in stdin.lock().lines() { println!("{}", line.unwrap()); } }

Rust 0.10-0.12 (ver documentation ):

use std::io; fn main() { for line in io::stdin().lines() { print!("{}", line.unwrap()); } }

Rust 0.9 (ver documentación 0.9 ):

use std::io; use std::io::buffered::BufferedReader; fn main() { let mut reader = BufferedReader::new(io::stdin()); for line in reader.lines() { print(line); } }

Rust 0.8:

use std::io; fn main() { let lines = io::stdin().read_lines(); for line in lines.iter() { println(*line); } }

Rust 0.7:

use std::io; fn main() { let lines = io::stdin().read_lines(); for lines.iter().advance |line| { println(*line); } }