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