จะอ่านจากอินพุตมาตรฐานทีละบรรทัดได้อย่างไร?


91

สูตร Scala สำหรับการอ่านทีละบรรทัดจากอินพุตมาตรฐานคืออะไร? สิ่งที่เหมือนกับรหัสจาวาที่เทียบเท่า:

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

คำตอบ:


130

วิธีการมากที่สุดตรงมองไปข้างหน้าก็จะใช้ซึ่งเป็นส่วนหนึ่งของreadLine() Predefอย่างไรก็ตามมันค่อนข้างน่าเกลียดเนื่องจากคุณต้องตรวจสอบค่า null ในที่สุด:

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

นี่เป็นรายละเอียดมากคุณควรใช้java.util.Scannerแทน

ฉันคิดว่าวิธีที่สวยกว่าจะใช้scala.io.Source:

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

3
วิธีการ readLine ของ Predef เลิกใช้งานตั้งแต่ 2.11.0 ตอนนี้ขอแนะนำให้ใช้วิธีการในscala.io.StdIn
nicolastrres

1
@itemState โปรแกรมของฉันไม่สิ้นสุดถ้าฉันใช้ "io.Source.stdin.getLines" จะเข้าสู่โหมดรอ ... จะจัดการอย่างไร ...
ราชา

53

Console.readLineสำหรับคอนโซลคุณสามารถใช้ คุณสามารถเขียน (ถ้าคุณต้องการหยุดในบรรทัดว่าง):

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

หากคุณ cat ไฟล์เพื่อสร้างอินพุตคุณอาจต้องหยุดที่ค่าว่างหรือว่างโดยใช้:

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

ฉันรู้เกี่ยวกับ Console.readLine () ฉันกำลังมองหาสูตรอาหารที่กำหนด วิธี "scala" สำหรับการอ่านทีละบรรทัดจากอินพุตมาตรฐาน
Andrei Ciobanu

11
ฉันคิดว่าคุณหมายถึงtakeWhile(_ != null)
Seth Tisue

1
ขึ้นอยู่กับว่าคุณต้องการหยุดอย่างไร การมองหาบรรทัดว่างมักจะเป็นทางออกที่ง่ายที่สุด
Landei

4
โปรดทราบว่าจาก Scala 2.11.0 Console.readLineเลิกใช้งานแล้วให้ใช้StdIn.readlineแทน
BartłomiejSzałach

หรือ.takeWhile(Option(_).nonEmpty)อาจจะรู้สึกดีขึ้นในกรณีที่คุณต้องการหลีกเลี่ยงnullคำหลักอย่างสมบูรณ์
Conny

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

6
io.Source.stdinถูกกำหนดไว้ (ในscala.io.Sourceคลาส) def stdin = fromInputStream(System.in)ดังนั้นจึงควรยึดติดกับไฟล์io.Source.stdin.
Nader Ghanbari

ดูเหมือนจะใช้ไม่ได้กับ Scala 2.12.4 หรือฉันไม่พบสิ่งที่ถูกต้องในการนำเข้า
akauppi

ใช้งานได้ใน Scala 2.12 เพียงแค่ว่าcollectวิธีการนั้นเปลี่ยนไปด้วยคำตอบนี้ดังนั้นคุณต้องเรียกinput.getLinesซึ่งจะให้Iteratorไฟล์. คุณสามารถบังคับให้เป็นจริงโดยใช้.toStreamหรือใช้.toListขึ้นอยู่กับกรณีการใช้งาน
Nader Ghanbari

11

เวอร์ชันเรียกซ้ำ (คอมไพเลอร์ตรวจพบการเรียกซ้ำหางเพื่อปรับปรุงการใช้ฮีป)

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

หมายเหตุการใช้งานio.StdInจาก Scala 2.11 นอกจากนี้โปรดทราบว่าด้วยวิธีนี้เราสามารถสะสมอินพุตของผู้ใช้ในคอลเล็กชันที่ส่งคืนในที่สุด - นอกเหนือจากการพิมพ์ออกมา ได้แก่

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

คุณไม่สามารถใช้

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

มีให้ที่นี่: Scaladoc API


สิ่งนี้ไม่เทียบเท่ากับรหัสที่นำเสนอด้วย loop
techkuz

1

ตามที่ระบุไว้สั้น ๆ ในความคิดเห็นอื่น ๆscala.Predef.readLine()เลิกใช้งานตั้งแต่ Scala 2.11.0 และคุณสามารถแทนที่ด้วย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 != "")
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.