Comment lire une entrée standard ligne par ligne?

91

Quelle est la recette Scala pour lire ligne par ligne à partir de l'entrée standard? Quelque chose comme le code java équivalent:

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
la source

Réponses:

130

L'approche la plus simple utilisera simplement readLine()ce qui fait partie de Predef. cependant c'est plutôt moche car vous devez vérifier la valeur nulle éventuelle:

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

c'est tellement verbeux que vous préférez utiliser à la java.util.Scannerplace.

Je pense qu'une approche plus jolie utilisera scala.io.Source:

object ScannerTest {
  def main(args: Array[String]) {
    for (ln <- io.Source.stdin.getLines) println(ln)
  }
}
itemState
la source
3
la méthode readLine de Predef est obsolète depuis la 2.11.0, il est maintenant recommandé d'utiliser la méthode dansscala.io.StdIn
nicolastrres
1
@itemState mon programme ne se termine pas, si j'utilise, "io.Source.stdin.getLines" passe en mode attente ... comment gérer cela ...
Raja
53

Pour la console, vous pouvez utiliser Console.readLine. Vous pouvez écrire (si vous voulez vous arrêter sur une ligne vide):

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

Si vous créez un fichier pour générer l'entrée, vous devrez peut-être vous arrêter sur null ou vide en utilisant:

@inline def defined(line: String) = {
  line != null && line.nonEmpty
}
Iterator.continually(Console.readLine).takeWhile(defined(_)).foreach(line => println("read " + line))
Landei
la source
Je connais Console.readLine (), je recherche une recette donnée. La méthode "scala" pour lire ligne par ligne à partir de l'entrée Standard.
Andrei Ciobanu
11
Je pense que vous voulez diretakeWhile(_ != null)
Seth Tisue
1
Cela dépend de la façon dont vous voulez vous arrêter. La recherche d'une ligne vide est souvent la solution la plus simple.
Landei le
4
Notez que de Scala 2.11.0 Console.readLineest obsolète, utilisez à la StdIn.readlineplace.
Bartłomiej Szałach
Ou .takeWhile(Option(_).nonEmpty)vous vous sentirez peut-être mieux au cas où vous voudriez éviter nullcomplètement le mot - clé.
conny
27
val input = Source.fromInputStream(System.in);
val lines = input.getLines.collect
Jason
la source
6
io.Source.stdinest défini (en scala.io.Sourceclasse) comme il est def stdin = fromInputStream(System.in)donc probablement préférable de s'en tenir au io.Source.stdin.
Nader Ghanbari
Cela ne semble pas fonctionner avec Scala 2.12.4, ou je n'ai pas trouvé les bons éléments à importer.
akauppi
Cela fonctionne dans Scala 2.12, juste que la collectméthode soit modifiée sicne cette réponse donc vous devez simplement appeler input.getLinesce qui vous donne un Iterator. Vous pouvez le forcer à se matérialiser en utilisant .toStreamou .toListdessus, selon le cas d'utilisation.
Nader Ghanbari
11

Une version récursive (le compilateur détecte une récursivité de queue pour une meilleure utilisation du tas),

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

Notez l'utilisation de io.StdInde Scala 2.11. Notez également qu'avec cette approche, nous pouvons accumuler les entrées utilisateur dans une collection qui est finalement retournée - en plus d'être imprimée. À savoir,

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]())
}
orme
la source
10

Ne peux-tu pas utiliser

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

Disponible ici: API Scaladoc

kaning
la source
ce n'est pas équivalent au code présenté avec boucle
techkuz
1

Comme indiqué brièvement dans d'autres commentaires, scala.Predef.readLine()est obsolète depuis Scala 2.11.0, et vous pouvez le remplacer par 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
la source