¿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());
        }
    }
}
Andrei Ciobanu
fuente

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)
  }
}
itemState
fuente
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))
Landei
fuente
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
Jason
fuente
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]())
}
olmo
fuente
10

No puedes usar

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

Disponible aquí: API Scaladoc

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