Reading console input in Kotlin
Asked Answered
L

9

81

I am attempting to accept input from the console in Kotlin but it is difficult because I am not too sure about the syntax.

I begin with the main

fun main(args: Array<String>) {

}

WHAT should I enter after this? I am aware that the println() and readline() are involved but I do not know how to structure them.

Objective: prompt user to enter a number, the number entered is multiplied by 6, program returns the result to the console display.

Lafontaine answered 22/12, 2016 at 12:39 Comment(0)
K
157

Note that since Kotlin 1.6 readLine()!! should be replaced with readln().

Here are A+B examples in Kotlin reading from stdin:

fun main() {
  val (a, b) = readLine()!!.split(' ')
  println(a.toInt() + b.toInt())
}

or

fun main(vararg args: String) {
  val (a, b) = readLine()!!.split(' ').map(String::toInt)
  println(a + b)
}

or

fun readInts() = readLine()!!.split(' ').map { it.toInt() }

fun main(vararg args: String) {
  val (a, b) = readInts()
  println(a + b)
}

or

import java.util.Scanner

fun main() {
  val input = Scanner(System.`in`)
  val a = input.nextInt()
  val b = input.nextInt()
  println(a + b)
}

or

with(Scanner(System.`in`)) {
    val a = nextInt()
    val b = nextInt()
    println(a + b)
}

Competitive programming

Must-read intro: https://kotlinlang.org/docs/tutorials/competitive-programming.html

Must-watch Kotlin productivity videos: https://www.jetbrains.com/icpc/

Here is an (inspired by the article) extended bunch of helper functions for reading all possible types, lists, arrays, 2d-arrays, etc:

private fun readln() = readLine()!!
private fun readlnByte() = readln().toByte()
private fun readlnShort() = readln().toShort()
private fun readlnInt() = readln().toInt()
private fun readlnLong() = readln().toLong()
private fun readlnFloat() = readln().toFloat()
private fun readlnDouble() = readln().toDouble()
private fun readlnBigInt(radix: Int = 10) = readln().toBigInteger(radix)
private fun readlnBigDecimal() = readln().toBigDecimal()

private fun lineSequence(limit: Int = Int.MAX_VALUE) = generateSequence { readLine() }.constrainOnce().take(limit)
private fun readlnStrings() = readln().split(' ')
private fun readlnBytes() = readlnStrings().map { it.toByte() }
private fun readlnShorts() = readlnStrings().map { it.toShort() }
private fun readlnInts() = readlnStrings().map { it.toInt() }
private fun readlnLongs() = readlnStrings().map { it.toLong() }
private fun readlnFloats() = readlnStrings().map { it.toFloat() }
private fun readlnDoubles() = readlnStrings().map { it.toDouble() }

private fun readByteArray() = readlnStrings().run { ByteArray(size) { get(it).toByte() } }
private fun readShortArray() = readlnStrings().run { ShortArray(size) { get(it).toShort() } }
private fun readIntArray() = readlnStrings().run { IntArray(size) { get(it).toInt() } }
private fun readLongArray() = readlnStrings().run { LongArray(size) { get(it).toLong() } }
private fun readFloatArray() = readlnStrings().run { FloatArray(size) { get(it).toFloat() } }
private fun readDoubleArray() = readlnStrings().run { DoubleArray(size) { get(it).toDouble() } }

private fun readlnByteArray(n: Int) = ByteArray(n) { readlnByte() }
private fun readlnShortArray(n: Int) = ShortArray(n) { readlnShort() }
private fun readlnIntArray(n: Int) = IntArray(n) { readlnInt() }
private fun readlnLongArray(n: Int) = LongArray(n) { readlnLong() }
private fun readlnFloatArray(n: Int) = FloatArray(n) { readlnFloat() }
private fun readlnDoubleArray(n: Int) = DoubleArray(n) { readlnDouble() }

private fun readByteArray2d(rows: Int, cols: Int) = Array(rows) { readByteArray().also { require(it.size == cols) } }
private fun readShortArray2d(rows: Int, cols: Int) = Array(rows) { readShortArray().also { require(it.size == cols) } }
private fun readLongArray2d(rows: Int, cols: Int) = Array(rows) { readLongArray().also { require(it.size == cols) } }
private fun readIntArray2d(rows: Int, cols: Int) = Array(rows) { readIntArray().also { require(it.size == cols) } }
private fun readFloatArray2d(rows: Int, cols: Int) = Array(rows) { readFloatArray().also { require(it.size == cols) } }
private fun readDoubleArray2d(rows: Int, cols: Int) = Array(rows) { readDoubleArray().also { require(it.size == cols) } }

private fun isWhiteSpace(c: Char) = c in " \r\n\t"

// JVM-only targeting code follows next

// readString() via sequence is still slightly faster than Scanner
private fun readString() = generateSequence { System.`in`.read().toChar() }
        .dropWhile { isWhiteSpace(it) }.takeWhile { !isWhiteSpace(it) }.joinToString("")
private fun readByte() = readString().toByte()
private fun readShort() = readString().toShort()
private fun readInt() = readString().toInt()
private fun readLong() = readString().toLong()
private fun readFloat() = readString().toFloat()
private fun readDouble() = readString().toDouble()
private fun readBigInt(radix: Int = 10) = readString().toBigInteger(radix)
private fun readBigDecimal() = readString().toBigDecimal()

private fun readBytes(n: Int) = generateSequence { readByte() }.take(n)
private fun readShorts(n: Int) = generateSequence { readShort() }.take(n)
private fun readInts(n: Int) = generateSequence { readInt() }.take(n)
private fun readLongs(n: Int) = generateSequence { readLong() }.take(n)
private fun readFloats(n: Int) = generateSequence { readFloat() }.take(n)
private fun readDoubles(n: Int) = generateSequence { readDouble() }.take(n)

Beware that Scanner is somewhat slow. This may be important in some cases like competitive programming where program's execution on large inputs could be made up to two times faster just by replacing Scanner with plain readLine. Even my suboptimal readString() implementation tokenizing via sequence is slightly faster. It allows to read input tokens until any next whitespace unlike Kotlin's built-in readLine().

I hope someday a concise, crossplatform, performant, universal for both console and files input parsing support would be introduced in Kotlin stdlib. Like readInt, readLong, etc global and Reader extension functions. This would be very userful not only for competitive programming but also for learning Kotlin as first language. A concept of reading a number shouldn't require first explaining collections, lambdas and monads.


Bonus

Sometimes you start with console input/output but then need to switch to files. It becomes too tedious to prepend every read or write call with file stream variable.

Here is a peace of Kotlin magic that allows to just wrap unchanged console code with a couple of lines to force it read and write to files also ensuring they are closed properly:

fun <T : Closeable, R> T.useWith(block: T.() -> R): R = use { with(it, block) }

File("a.in").bufferedReader().useWith {
    File("a.out").printWriter().useWith {
        val (a, b) = readLine()!!.split(' ').map(String::toInt)
        println(a + b)
    }
}

Scanner(File("b.in")).useWith {
    PrintWriter("b.out").useWith {
        val a = nextInt()
        val b = nextInt()
        println(a + b)
    }
}

Wrapping lines can be quickly commented out when happens a need to switch back to console.

Kippy answered 22/12, 2016 at 12:49 Comment(7)
Thank You. May I have the link to these ?Lafontaine
@siur, discuss.kotlinlang.org/t/taking-inputs/152/2, kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/read-line.html, github.com/JetBrains/kotlin/blob/master/libraries/stdlib/src/…Kippy
Here is more real examples: codeforces.com/blog/entry/45454?#comment-300490Kippy
The Scanner is the best oneCredits
Why have you used such complex examples? simple questions need simple answers.The question was to read from console only. what he mentioned as objective was supposed to be "his objective" not yours!Noneffective
@SimpleFellow, I've used this slightly weak question to share several simple approaches with bonus extra knowledge benefittable for wider audience than just a single asker. I think it is what SO is all about. I've seen here many popular very detailed answers so far, but the compaint for the quality with a downvote is a kind of novelty. ) Feel free to provide a simplier answer, or a better one, or both. )Kippy
If somebody want to use Kotlin for CP, the System.`in`.bufferedReader().readLine()!! is the fastest one. I had multiple test cases failed because of std-lib's readLine()!! is slow.Retsina
W
8

Use readLine() to take input from user, ATQ:

fun main(args:Array<String>){
    print("Enter a number")
    var variableName:Int = readLine()!!.toInt()  // readLine() is used to accept the String value and ".toInt()" will convert the string to  Int. 
    var result:Int= variableName*6
    print("The output is:$result") 
}
Westmoreland answered 3/8, 2017 at 17:15 Comment(0)
P
6

There are multiple alternatives to handle Console I/O with Kotlin.

1. Using the Kotlin Standard Library: The Kotlin standard library provides us extensions to handling I/O based on the classes of the JDK.

To print in the console we can use the print function. If we run the following snippet:

print("Hello from Kotlin")

We’ll see the following message displayed on our terminal:

Hello from Kotlin

Behind-the-scenes this function uses the Java System.out.print method. Also, the library offers us the println alternative function, witch adds the line separator at the end of the message.

In order to read from the console, we can use readLine function:

val inputText = readLine()

2. Using the Java Standard Library: Kotlin has great interoperability with Java. Thus, we can use the standard I/O classes from the JDK in our programs in case we need them.

2.1. Using the Scanner Class: Using the Scanner class is very straightforward; we only need to create an instance and use the nextLine method:

val scanner = Scanner(System.`in`)

val readText = scanner.nextLine()

Note that we are escaping the in property with backticks because it’s a keyword in Kotlin.

2.2. Using the BufferedReader Class: To use the BufferedReader class to read from the standard input stream, we first need to instantiate with System.in:

val reader = BufferedReader(InputStreamReader(System.`in`))

And then we can use its methods — for example, readLine():

val readText = reader.readLine()

2.3. Using the Console Class: Unlike the two previous classes, the Console class has additional methods for handling console I/O, like readPassword and printf.

In order to use the Console class we need to get the instance from the System class:

val console = System.console()

val readText = console.readLine()

Also, thanks to Kotlin’s interoperability with Java, we can use additional Java libraries for handling I/O.

In your case, after reading the input you can convert the String value to Int using the toInt() function.

Panathenaea answered 16/4, 2019 at 0:24 Comment(0)
T
3
fun readInts(separator: Char = ' ') = 
readLine()!!.split(separator).map(String::toInt)
fun main(args: Array<String>) {
    var A : List<Int> = readInts()
}
Turmoil answered 2/11, 2017 at 22:56 Comment(0)
L
2

By default readLine takes input as string toInt can be used to convert it to integer

fun main(args:Array<String>){
    var first: Int
    var second: Int
    println("Enter the first number")
    first = readLine()!!.toInt()
    println("Enter the second number")
    second= readLine()!!.toInt()
    println("The sum is ${first + second}")
}
Lindstrom answered 4/10, 2018 at 11:55 Comment(0)
D
1

Below is the basic function to take the system input

fun main(args: Array<String>) {
    val sc = Scanner(System.`in`)
    val num1 = sc.nextInt()
    val num2 = sc.nextInt()
    val sum = solveMeFirst(num1, num2)
    println(sum)
}
Diabolize answered 7/11, 2021 at 13:55 Comment(0)
C
0

Just create a scan function

  fun scan():String{
    var str ="";
    while ( str==""){
        str = readLine().toString()
    }
    return str;
 }

Use like

fun main() {
    println("Enter number 1")
    val a = scan().toInt()
    println("Enter number 2")
    val b = scan().toInt()
    println(a + b);
}
Calcicole answered 22/7, 2021 at 8:50 Comment(0)
R
0

You can use readLine().

fun main(args: Array<String>) {
    println("What's your name?")
    val inputText = readLine()
    println(“Your name is " + inputText)
}
Raycher answered 26/8, 2021 at 12:38 Comment(0)
C
0

Changes:

The readLine()!! function has been changed to readLine(). This function can now return a null value. The readln() function has been changed to readlnOrNull(). This function can also return a null value.

examples :

readln() ->

println("What is your nickname?")
val nickname = readln()
println("Hello, $nickname!")

readlnOrNull() ->

var sum = 0
while (true) {
    val nextLine = readlnOrNull().takeUnless { 
        it.isNullOrEmpty() 
    } ?: break
    sum += nextLine.toInt()
}
println(sum)

source : https://kotlinlang.org/docs/whatsnew16.html#new-readline-functions

Conias answered 22/3 at 13:54 Comment(1)
That's not correct. Please have a look again at the link that you attribute as the source for your answer. Also your answer doesn't seem to add anything new to what was already said in the top-rated answer. That's not enough to support an answer, if you do not have anything else to contribute that is relevant to the question.Hallucinate

© 2022 - 2024 — McMap. All rights reserved.