从扩展名中突变字符串

我试图将一个Swift脚本移植到Kotlin,但是它并没有像预期的那样工作,代码所做的是在条件为真(需要解析器)时使用字符串。 在Swift中它可以正常工作,但是在Kotlin中却不行(我刚刚在一个月前开始使用Kotlin,所以也许我错过了一些东西)。

迅速

extension String { @discardableResult public mutating func consumeWhile(test: (String) -> Bool) -> String { var chars = [Character](self.characters) var result = "" while chars.count > 0 && test(String(chars[0])) { result.append(chars.remove(at: 0)) } self = String(chars) return result } } 

科特林

 fun String.consumeWhile(test: (String) -> Boolean): String { if (isEmpty()) return "" val chars = toCharArray().toMutableList() var result = "" var i = -1 while (chars.isNotEmpty() && test(chars.first().toString())) { result += chars.removeAt(0) ++i } removeRange(0..i) return result } 

所以基本用法看起来像

 val myString = "--Test" // IntelliJ suggests change var to val val consumedString = myString.consumeWhile{ it != "-" } println("result: $myString consumedString: $consumedString") // expected: "result: Test consumedString: --" // but got: "result: --Test consumedString: --" 

编辑:感谢所有的答案,不知道是否可以像我想要的那样做,因为提到的字符串在Kotlin / Java(只使用相同的字符串)是不可变的。

我忘了提及,我需要消费的字符串,基本上是B / C我做一个解析器,所以我需要存储消费的字符和突变的字符串。 我将留下这个问题,但我最终创建了一个只实现了几个String类方法的类。

 class Line(var string: String) { val length: Int get() = string.length fun consumeWhile(test: (String) -> Boolean): String { if (string.isEmpty()) return "" val chars = string.toCharArray().toMutableList() var result = "" while (chars.isNotEmpty() && test(chars.first().toString())) { result += chars.removeAt(0) } string = chars.joinToString("") return result } fun isNullOrEmpty(): Boolean { return string.isNullOrEmpty() } fun isNotEmpty(): Boolean { return string.isNotEmpty() } private fun removeRange(range: IntRange) { string = string.removeRange(range) } operator fun get(i: Int): Char { return string[i] } } 

用法示例

 val line = Line(string) if (line.isNotEmpty() && line[0].toString() == "(") { line.consumeWhile { it == "(" } while (line.isNotEmpty() && line[0].toString() != ")") { line.consumeWhile { it == " " } val key = line.consumeWhile { it != "=" } line.consumeWhile { it == "\"" || it == "=" } val value = line.consumeWhile { it != "\"" } line.consumeWhile { it == "\"" } attributes[key] = value } line.consumeWhile { it == ")" } } 

在Java和Kotlin中, String都是不可变的,创建后不能更改。

在swift中,这大概可以通过mutating修饰符关闭。 但是在Kotlin中, removeRange(0..i)会创建一个新的String对象,然后将其丢弃。

要使其表现得如您所愿,您将需要:

  1. 创建一个包含可被替换的字符串的包装对象。
  2. 返回分割字符串和其余的一Pair ,然后可以使用解构运算符将其分配为[_, myString] = myString.consumeWhile {}

Kotlin字符串是不可改变的,不能被修改。 相反,您可以创建一个新的字符串并将其返回

 fun String.consumeWhile(test: (String) -> Boolean): String { if (isEmpty()) return "" val chars = toCharArray().toMutableList() while (chars.isNotEmpty() && test(chars.first().toString())) { chars.removeAt(0) // Do something with the char } return chars.joinToString(separator = "") } 

另外,除非我误解,你的测试条件应该是it == "-"来得到你想要的结果:

 val myString = "--Test" val newString = myString.consumeWhile{ it == "-" } println("result: $newString") 

字符串在Kotlin和Java中是不可变的,所以无论如何你都不能修改它的状态。

您应该避免重复制作轮子,在Kotlin中有一个现有的函数String#dropWhile(Char) 。 你需要做的一件事是反转条件,例如:

 val result = "--Test".dropWhile { it == '-' } // ^--- "Test" 

你用

 myString.consumeWhile{ it != "-" } 

一旦遇到第一个“ – ”就停止消费,因此没有什么可做的了。

代码的工作原理,如果你使用

 myString.consumeWhile{ it == "-" } 

你会得到正确的预期输出。

我最终创建了一个只实现了几个String类方法的类。

 class Line(var string: String) { val length: Int get() = string.length fun consumeWhile(test: (String) -> Boolean): String { if (string.isEmpty()) return "" val chars = string.toCharArray().toMutableList() var result = "" while (chars.isNotEmpty() && test(chars.first().toString())) { result += chars.removeAt(0) } string = chars.joinToString("") return result } fun isNullOrEmpty(): Boolean { return string.isNullOrEmpty() } fun isNotEmpty(): Boolean { return string.isNotEmpty() } private fun removeRange(range: IntRange) { string = string.removeRange(range) } operator fun get(i: Int): Char { return string[i] } } 

用法示例

 val line = Line(string) if (line.isNotEmpty() && line[0].toString() == "(") { line.consumeWhile { it == "(" } while (line.isNotEmpty() && line[0].toString() != ")") { line.consumeWhile { it == " " } val key = line.consumeWhile { it != "=" } line.consumeWhile { it == "\"" || it == "=" } val value = line.consumeWhile { it != "\"" } line.consumeWhile { it == "\"" } attributes[key] = value } line.consumeWhile { it == ")" } } 

Obs:现在会标记为已回答,直到有更好的解决方案出来