Como ler a entrada padrão linha por linha?

90

Qual é a receita do Scala para ler linha por linha da entrada padrão? Algo como o 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
fonte

Respostas:

130

A abordagem mais simples usará apenas o readLine()que faz parte Predef. no entanto, isso é bastante feio, pois você precisa verificar se há algum valor nulo:

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

isso é tão detalhado que você prefere usar java.util.Scanner.

Acho que uma abordagem mais bonita usará scala.io.Source:

object ScannerTest {
  def main(args: Array[String]) {
    for (ln <- io.Source.stdin.getLines) println(ln)
  }
}
itemState
fonte
3
o método readLine de Predef foi descontinuado desde 2.11.0, agora é recomendado usar o método emscala.io.StdIn
nicolastrres
1
@itemState meu programa não está terminando, se eu usar "io.Source.stdin.getLines" indo para o modo de espera ... como faço para lidar com isso ...
Raja
53

Para o console, você pode usar Console.readLine. Você pode escrever (se quiser parar em uma linha vazia):

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

Se você catar um arquivo para gerar a entrada, pode ser necessário parar em nulo ou vazio usando:

@inline def defined(line: String) = {
  line != null && line.nonEmpty
}
Iterator.continually(Console.readLine).takeWhile(defined(_)).foreach(line => println("read " + line))
Landei
fonte
Eu conheço Console.readLine (), estou procurando uma determinada receita. A maneira "scala" para ler linha por linha da entrada padrão.
Andrei Ciobanu
11
Eu acho que você quer dizertakeWhile(_ != null)
Seth Tisue
1
Depende de como você deseja parar. A procura de uma linha vazia costuma ser a solução mais simples.
Landei
4
Observe que Scala 2.11.0 Console.readLineestá obsoleto, use em seu StdIn.readlinelugar.
Bartłomiej Szałach
Ou .takeWhile(Option(_).nonEmpty)pode se sentir melhor caso queira evitar nullcompletamente a palavra - chave.
conny
27
val input = Source.fromInputStream(System.in);
val lines = input.getLines.collect
Jason
fonte
6
io.Source.stdiné definido (na scala.io.Sourceaula), def stdin = fromInputStream(System.in)então provavelmente é melhor continuar com o io.Source.stdin.
Nader Ghanbari
Isso não parece funcionar com o Scala 2.12.4, ou não encontrei as coisas certas para importar.
akauppi
Ele funciona no Scala 2.12, apenas que o collectmétodo é alterado após essa resposta, então você só precisa chamar o input.getLinesque lhe dá um Iterator. Você pode forçá-lo a se materializar usando .toStreamou .toListsobre ele, depende do caso de uso.
Nader Ghanbari
11

Uma versão recursiva (o compilador detecta uma recursão final para melhorar o uso de heap),

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

Observe o uso de io.StdInScala 2.11. Observe também que, com essa abordagem, podemos acumular a entrada do usuário em uma coleção que é eventualmente retornada - além de ser impressa. Nomeadamente,

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
fonte
10

Você não pode usar

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

Conforme disponível aqui: API Scaladoc

Kaning
fonte
isto não é equivalente ao código apresentado com loop
techkuz
0

Conforme observado brevemente em outros comentários, scala.Predef.readLine()está obsoleto desde Scala 2.11.0 e você pode substituí-lo por scala.io.StdIn.readLine():

// Read STDIN lines until a blank one
import scala.io.StdIn.readLine

var line = ""
do {
  line = readLine()
  println("Read: " + line)
} while (line != "")
Brad Solomon
fonte