2017-07-14 73 views
1

我試圖將一個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 == ")" } 
} 

回答

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

觀測數據:現在會標記爲回答,直到一個更好的解決方案出來

0

在Java和科特林String是不可改變的,它已被創建之後,你不能改變它。

在迅速此推測可以通過mutating改性劑截止。但是在Kotlin removeRange(0..i)中創建了一個新的String對象,然後您將丟棄它。

把它表現得你想你將需要:

  1. 創建包含可以被替換字符串的包裝對象。
  2. 返回兩個分割字符串,其餘爲Pair,然後你可以用解構運營商將其指定爲​​3210
+0

這似乎有趣,我已經沒想到那種方法,會嘗試一下。還請查看我更新的問題,並附上一些進一步的解釋。 – norman784

+0

雖然有效,但結果有點難看,現在您無法將元組/對輸出分配到現有變量中,您需要將返回值分配給新變量,即:val string =「Test」; val(_,newString)= string.consumeWhile {...}; val(_,newString2)= newString.consumeWhile {...}; – norman784

0

科特林字符串是不可改變的,不能就地進行修改。相反,你可以創建一個新的字符串,並將其返回

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

檢查我更新的問題 – norman784

0

字符串是不可改變的科特林& Java,所以你無法修改它的狀態。

你應該避免使車輪反覆,有在科特林現有功能String#dropWhile(Char)。有一件事你需要做的是反轉的條件,例如:

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

我試過dropWhile,但正如我在更新問題中提到的,我需要更新的輸入字符串和輸出字符串。 – norman784

+0

@ norman784嗨,沒有問題。因爲'dropWhile'不是返回一個新的'String'。它根本不會改變你的'string'狀態,因爲'String'是我提到的一個不可變的類。你需要做的一件事是將結果重新分配給'string',例如:'string = string.dropWhile {test(it)}' –

+0

是的,但有時候我也需要que消費的字符串,所以這不會符合我的需求。 Regards – norman784

0

您使用

myString.consumeWhile{ it != "-" } 

它便會立即停止,因爲它滿足了第一個消費「 - 」,因此它沒什麼更多的事情要做。

代碼工作,因爲它應該,如果你使用

myString.consumeWhile{ it == "-" } 

你會得到預期的輸出是正確的。

+0

我試過這種方式,但我需要更新myString var b/c我建立一個解析器,檢查更新的問題 – norman784

相關問題