Как читать из стандартного ввода построчно?

91

Каков рецепт Scala для построчного чтения со стандартного ввода? Что-то вроде эквивалентного java-кода:

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. однако это довольно уродливо, поскольку вам нужно проверить возможное нулевое значение:

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)
  }
}
itemState
источник
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))

Если вы отправляете файл для генерации ввода, вам может потребоваться остановиться либо на null, либо на пустом, используя:

@inline def defined(line: String) = {
  line != null && line.nonEmpty
}
Iterator.continually(Console.readLine).takeWhile(defined(_)).foreach(line => println("read " + line))
Landei
источник
Я знаю про Console.readLine (), ищу заданный рецепт. Способ "scala" для построчного чтения из стандартного ввода.
Андрей Чобану
11
Я думаю, вы имеете в видуtakeWhile(_ != null)
Сет Тисью
1
Зависит от того, как вы хотите остановиться. Поиск пустой строки часто является самым простым решением.
Landei 04
4
Обратите внимание, что из Scala 2.11.0 Console.readLineустарел, используйте StdIn.readlineвместо него.
Bartłomiej Szał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.
Надер Ганбари
Похоже, это не работает со Scala 2.12.4, или я не нашел нужных вещей для импорта.
akauppi
Он работает в Scala 2.12, просто collectметод изменен в этом ответе, поэтому вам нужно просто вызвать, input.getLinesкоторый дает вам Iterator. Вы можете заставить его материализоваться с помощью .toStreamили .toListна нем, в зависимости от варианта использования.
Надер Ганбари
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

Канинг
источник
это не эквивалент представленного кода с циклом
techkuz