Bagaimana cara membaca dari baris masukan standar demi baris?

91

Apa resep Scala untuk membaca baris demi baris dari input standar? Sesuatu seperti kode java yang setara:

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
sumber

Jawaban:

130

Pendekatan yang paling lurus ke depan hanya akan menggunakan readLine()yang merupakan bagian dari Predef. Namun itu agak jelek karena Anda perlu memeriksa nilai null akhirnya:

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

ini sangat bertele-tele, Anda lebih suka menggunakannya java.util.Scanner.

Saya pikir pendekatan yang lebih cantik akan menggunakan scala.io.Source:

object ScannerTest {
  def main(args: Array[String]) {
    for (ln <- io.Source.stdin.getLines) println(ln)
  }
}
itemState
sumber
3
metode readLine of Predef tidak digunakan lagi sejak 2.11.0, sekarang disarankan untuk menggunakan metode discala.io.StdIn
nicolastrres
1
@itemState Program saya tidak berakhir, jika saya menggunakan, "io.Source.stdin.getLines" akan menunggu mode ... bagaimana menangani ini ...
Raja
53

Untuk konsol, Anda dapat menggunakan Console.readLine. Anda dapat menulis (jika Anda ingin berhenti di baris kosong):

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

Jika Anda membuat file untuk menghasilkan input, Anda mungkin perlu berhenti pada null atau kosong menggunakan:

@inline def defined(line: String) = {
  line != null && line.nonEmpty
}
Iterator.continually(Console.readLine).takeWhile(defined(_)).foreach(line => println("read " + line))
Landei
sumber
Saya tahu tentang Console.readLine (), saya mencari resep yang diberikan. Cara "skala" untuk membaca baris demi baris dari input Standar.
Andrei Ciobanu
11
Saya pikir maksud AndatakeWhile(_ != null)
Seth Tisue
1
Tergantung bagaimana Anda ingin berhenti. Mencari baris kosong seringkali merupakan solusi paling sederhana.
Landei
4
Perhatikan bahwa dari Scala 2.11.0 Console.readLinetidak digunakan lagi, gunakan StdIn.readlinesaja.
Bartłomiej Szałach
Atau .takeWhile(Option(_).nonEmpty)mungkin merasa lebih baik jika Anda ingin menghindari nullkata kunci sepenuhnya.
conny
27
val input = Source.fromInputStream(System.in);
val lines = input.getLines.collect
Jason
sumber
6
io.Source.stdindidefinisikan (di scala.io.Sourcekelas) def stdin = fromInputStream(System.in)jadi mungkin lebih baik untuk tetap menggunakan io.Source.stdin.
Nader Ghanbari
Ini sepertinya tidak berfungsi dengan Scala 2.12.4, atau saya tidak menemukan hal yang tepat untuk diimpor.
akauppi
Ia bekerja di Scala 2.12, hanya saja collectmetodenya diubah sejak jawaban ini sehingga Anda hanya perlu memanggil input.getLinesyang memberi Anda Iterator. Anda dapat memaksanya untuk terwujud menggunakan .toStreamatau .toListdi atasnya, tergantung pada kasus penggunaan.
Nader Ghanbari
11

Versi rekursif (kompilator mendeteksi rekursi ekor untuk peningkatan penggunaan heap),

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

Perhatikan penggunaan io.StdIndari Scala 2.11. Perhatikan juga dengan pendekatan ini, kita dapat mengakumulasikan input pengguna dalam koleksi yang akhirnya dikembalikan - selain untuk dicetak. Yaitu,

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

Bisakah kamu tidak menggunakan

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

Seperti yang tersedia di sini: API Scaladoc

kaning
sumber
ini tidak sama dengan kode yang disajikan dengan loop
techkuz
1

Seperti disebutkan secara singkat di komentar lain, scala.Predef.readLine()tidak digunakan lagi sejak Scala 2.11.0, dan Anda dapat menggantinya dengan 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
sumber