¿Cómo leer una entrada estándar línea por línea?


91

¿Cuál es la receta de Scala para leer línea por línea desde la entrada estándar? Algo parecido al código java equivalente:

import java.util.Scanner; 

public class ScannerTest {
    public static void main(String args[]) {
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext()){
            System.out.println(sc.nextLine());
        }
    }
}

Respuestas:


130

El enfoque más sencillo solo usará lo readLine()que es parte de Predef. sin embargo, eso es bastante feo, ya que debe verificar el eventual valor nulo:

object ScannerTest {
  def main(args: Array[String]) {
    var ok = true
    while (ok) {
      val ln = readLine()
      ok = ln != null
      if (ok) println(ln)
    }
  }
}

esto es tan detallado, preferiría usarlo java.util.Scanneren su lugar.

Creo que se utilizará un enfoque más bonito scala.io.Source:

object ScannerTest {
  def main(args: Array[String]) {
    for (ln <- io.Source.stdin.getLines) println(ln)
  }
}

3
el método readLine of Predef quedó obsoleto desde 2.11.0, ahora se recomienda usar el método enscala.io.StdIn
nicolastrres

1
@itemState mi programa no termina, si uso, "io.Source.stdin.getLines" va al modo de espera ... ¿cómo manejar esto ...?
Raja

53

Para la consola puedes usar Console.readLine. Puede escribir (si desea detenerse en una línea vacía):

Iterator.continually(Console.readLine).takeWhile(_.nonEmpty).foreach(line => println("read " + line))

Si obtiene un archivo para generar la entrada, es posible que deba detenerse en nulo o vacío usando:

@inline def defined(line: String) = {
  line != null && line.nonEmpty
}
Iterator.continually(Console.readLine).takeWhile(defined(_)).foreach(line => println("read " + line))

Conozco Console.readLine (), estoy buscando una receta determinada. La forma "scala" de leer línea por línea desde la entrada estándar.
Andrei Ciobanu

11
Creo que te refierestakeWhile(_ != null)
Seth Tisú

1
Depende de cómo quieras parar. Buscar una línea vacía suele ser la solución más sencilla.
Landei

4
Tenga en cuenta que Scala 2.11.0 Console.readLineestá obsoleto, utilice StdIn.readlineen su lugar.
Bartłomiej Szałach

O .takeWhile(Option(_).nonEmpty)podría sentirse mejor en caso de que desee evitar la nullpalabra clave por completo.
conny

27
val input = Source.fromInputStream(System.in);
val lines = input.getLines.collect

6
io.Source.stdinestá definido (en scala.io.Sourceclase), por def stdin = fromInputStream(System.in)lo que probablemente sea mejor seguir con el io.Source.stdin.
Nader Ghanbari

Esto no parece funcionar con Scala 2.12.4, o no encontré las cosas correctas para importar.
akauppi

Funciona en Scala 2.12, solo que el collectmétodo se cambia en esta respuesta, por lo que solo tiene que llamar, lo input.getLinesque le da un archivo Iterator. Puede forzarlo a materializarse usando .toStreamo .toListsobre él, depende del caso de uso.
Nader Ghanbari

11

Una versión recursiva (el compilador detecta una recursividad de cola para mejorar el uso del montón),

def read: Unit = {
  val s = scala.io.StdIn.readLine()
  println(s)
  if (s.isEmpty) () else read 
}

Tenga en cuenta el uso de io.StdInScala 2.11. También tenga en cuenta que con este enfoque podemos acumular la entrada del usuario en una colección que finalmente se devuelve, además de imprimirse. A saber,

import annotation.tailrec

def read: Seq[String]= {

  @tailrec
  def reread(xs: Seq[String]): Seq[String] = {
    val s = StdIn.readLine()
    println(s)
    if (s.isEmpty()) xs else reread(s +: xs) 
  }

  reread(Seq[String]())
}

10

No puedes usar

var userinput = readInt // for integers
var userinput = readLine 
...

Disponible aquí: API Scaladoc


esto no es equivalente al código presentado con bucle
techkuz

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.