从扩展名变异字符串

时间:2017-07-14 19:23:48

标签: kotlin

我试图将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中是不可变的(只是使用相同的字符串)。 / p>

我忘了提到我需要消耗的字符串,基本上是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 == ")" }
}

5 个答案:

答案 0 :(得分:0)

在Java和Kotlin String中都是不可变的,在创建它之后就无法更改它。

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

要让它按照您的意愿行事,您需要:

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

答案 1 :(得分:0)

Kotlin字符串是不可变的,无法在适当的位置进行修改。相反,您可以创建一个新的String并将其返回

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

答案 2 :(得分:0)

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

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

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

答案 3 :(得分:0)

您使用

myString.consumeWhile{ it != "-" }

一旦遇到第一个" - "就会停止消费,因此无需再做任何事情。

如果使用

,代码可以正常工作
myString.consumeWhile{ it == "-" }

您将获得正确的预期输出。

答案 4 :(得分:0)

我最终创建了一个只实现几个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:现在将标记为已回答,直到找到更好的解决方案