在Kotlin中读取控制台输入

78

我正在尝试使用 Kotlin 从控制台接受输入,但由于对语法不是很确定,所以很困难。

我从 main 函数开始。

fun main(args: Array<String>) {

}

在这之后我应该输入什么?我知道println()readline()会被用到,但我不知道如何安排它们的结构。

目标:提示用户输入一个数字,将输入的数字乘以6,程序将结果返回给控制台显示。

8个回答

151
请注意,自 Kotlin 1.6 开始,readLine()!! 应替换为 readln()。以下是从 stdin 读取的 Kotlin A+B 示例:
fun main() {
  val (a, b) = readLine()!!.split(' ')
  println(a.toInt() + b.toInt())
}

或者

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

或者

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

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

或者

import java.util.Scanner

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

或者

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

竞赛编程

必读介绍: https://kotlinlang.org/docs/tutorials/competitive-programming.html

必看Kotlin生产力视频: https://www.jetbrains.com/icpc/

这里是(启发自文章的)扩展帮助函数的一堆,用于读取所有可能的类型、列表、数组、二维数组等:

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)

请注意Scanner的速度较慢。在一些情况下,这可能很重要,比如竞赛编程,通过用普通的readLine替换Scanner可以使程序在大输入上的执行速度提高两倍。即使是我次优的 readString()实现,通过序列分词也稍微快一点。它允许读取输入标记,直到下一个空格,而不像Kotlin内置的readLine()那样。

希望 Kotlin stdlib 中引入一种简洁、跨平台、高性能、适用于控制台和文件输入的通用解析支持,类似于全局的 readIntreadLong 等和 Reader 扩展函数。这不仅对竞赛编程非常有用,也适用于将 Kotlin 作为第一门语言学习。读取数字的概念不应该需要先解释集合、Lambda 和单子。


奖励

有时候你开始使用控制台输入/输出,但是后来需要切换到文件。 每次在读写调用之前添加文件流变量会变得太繁琐。

这里有一段 Kotlin 魔法代码,可以仅用几行包装未更改的控制台代码,强制其读取和写入文件,并确保它们被正确关闭:

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

当需要切换回控制台时,可以快速注释掉换行。


谢谢。我可以有这些的链接吗? - siur
1
Scanner 是最好的。 - voddan
为什么你使用了这么复杂的例子?简单的问题需要简单的答案。问题只是要从控制台读取。他提到的目标应该是“他的目标”,而不是你的! - Simple Fellow
3
@SimpleFellow,我使用了一个稍微有些弱的问题来分享几种简单的方法,并提供额外的知识内容,使受众更广泛而不仅仅是一个提问者。我认为这就是SO的全部意义。到目前为止,我看到了很多受欢迎的非常详细的答案,但对质量的投诉却是一种新奇的现象。请随意提供一个更简单或更好的答案,或两者都提供。 - Vadzim
1
如果有人想在竞赛编程中使用Kotlin,那么System.`in`.bufferedReader().readLine()!!是最快的方法。我曾经因为标准库的readLine()!!速度慢而导致多个测试用例失败。 - Animesh Sahu
显示剩余2条评论

8
使用readLine()从用户获取输入, 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") 
}

6

有多种方法可以处理Kotlin的控制台I/O。

1. 使用Kotlin标准库: Kotlin标准库提供了基于JDK类来处理I/O的扩展功能。

我们可以使用print函数在控制台中打印。如果我们运行以下代码片段:

print("Hello from Kotlin")

我们将在终端上看到以下消息显示:
Hello from Kotlin

在幕后,这个函数使用了Java中的System.out.print方法。此外,该库还提供了我们的替代功能println,它在消息末尾添加了行分隔符。

为了从控制台读取,我们可以使用readLine函数:

val inputText = readLine()

2. 使用Java标准库: Kotlin 与 Java 具有很好的互操作性。因此,我们可以在程序中使用 JDK 中的标准 I/O 类,以防需要使用它们。

2.1. 使用 Scanner 类: 使用 Scanner 类非常简单;我们只需要创建一个实例并使用 nextLine 方法:

val scanner = Scanner(System.`in`)

val readText = scanner.nextLine()

注意,我们使用反引号对in属性进行转义,因为它是Kotlin中的一个关键字。
2.2. 使用BufferedReader类:要使用BufferedReader类从标准输入流中读取内容,我们需要首先使用System.in实例化该类:
val reader = BufferedReader(InputStreamReader(System.`in`))

接着我们可以使用它的方法——例如,readLine()

val readText = reader.readLine()

2.3. 使用控制台类:与前两个类不同,Console 类有额外的方法来处理控制台 I/O,例如 readPasswordprintf

为了使用 Console 类,我们需要从 System 类获取实例:

val console = System.console()

val readText = console.readLine()

另外,由于Kotlin与Java的互操作性,我们可以使用额外的Java库来处理I/O。

在您的情况下,读取输入后,您可以使用 toInt() 函数将 String 值转换为 Int


3
fun readInts(separator: Char = ' ') = 
readLine()!!.split(separator).map(String::toInt)
fun main(args: Array<String>) {
    var A : List<Int> = readInts()
}

2

默认情况下,readLine将输入作为字符串处理,可以使用toInt将其转换为整数。

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}")
}

1
以下是获取系统输入的基本函数。
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)
}

0
你可以使用 readLine()
fun main(args: Array<String>) {
    println("What's your name?")
    val inputText = readLine()
    println(“Your name is " + inputText)
}

0

只需创建一个扫描函数

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

使用方法

fun main() {
    println("Enter number 1")
    val a = scan().toInt()
    println("Enter number 2")
    val b = scan().toInt()
    println(a + b);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接