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

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

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

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

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]())
}

10

Você não pode usar

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

Conforme disponível aqui: API Scaladoc


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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.