Come leggere riga per riga dallo standard input?


91

Qual è la ricetta di Scala per leggere riga per riga dallo standard input? Qualcosa di simile al codice 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());
        }
    }
}

Risposte:


130

L'approccio più diretto userà solo quello readLine()che fa parte di Predef. tuttavia è piuttosto brutto in quanto è necessario verificare l'eventuale valore nullo:

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

questo è così dettagliato, preferiresti usare java.util.Scannerinvece.

Penso che un approccio più carino utilizzerà scala.io.Source:

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

3
il metodo readLine di Predef è stato deprecato dalla 2.11.0, ora si consiglia di utilizzare il metodo inscala.io.StdIn
nicolastrres

1
@itemState il mio programma non finisce, se uso, "io.Source.stdin.getLines" va in modalità di attesa ... come gestirlo ...
Raja

53

Per la console puoi usare Console.readLine. Puoi scrivere (se vuoi fermarti su una riga vuota):

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

Se cat un file per generare l'input potrebbe essere necessario fermarsi su null o vuoto utilizzando:

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

Conosco Console.readLine (), sto cercando una determinata ricetta. Il modo "scala" per leggere riga per riga dallo Standard input.
Andrei Ciobanu

11
Penso che intenditakeWhile(_ != null)
Seth Tisue

1
Dipende da come vuoi fermarti. Cercare una riga vuota è spesso la soluzione più semplice.
Landei

4
Nota che da Scala 2.11.0 Console.readLineè deprecato, usa StdIn.readlineinvece.
Bartłomiej Szałach

Oppure .takeWhile(Option(_).nonEmpty)potresti sentirti meglio nel caso in cui desideri evitare nullcompletamente la parola chiave.
conny

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

6
io.Source.stdinè definito (in scala.io.Sourceclasse), def stdin = fromInputStream(System.in)quindi probabilmente è meglio attenersi al io.Source.stdin.
Nader Ghanbari

Questo non sembra funzionare con Scala 2.12.4, o non ho trovato le cose giuste da importare.
akauppi

Funziona in Scala 2.12, solo che il collectmetodo viene cambiato dopo questa risposta, quindi devi solo chiamare input.getLinesche ti dà un Iterator. Puoi costringerlo a materializzarsi usando .toStreamo .toListsu di esso, dipende dal caso d'uso.
Nader Ghanbari

11

Una versione ricorsiva (il compilatore rileva una ricorsione in coda per un migliore utilizzo dell'heap),

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

Notare l'uso di io.StdInda Scala 2.11. Nota anche che con questo approccio possiamo accumulare l'input dell'utente in una raccolta che alla fine viene restituita, oltre a essere stampata. Vale a dire,

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

Non puoi usare

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

Come disponibile qui: API Scaladoc


questo non è equivalente al codice presentato con loop
techkuz

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.