2

我有下面的代碼,其中,我傳遞字符串與類型"Hello|r World|g"的和下面的函數將其與"Hello"作爲在彩色red"World"被轉換爲attributedString顏色爲​​。我使用這個,因爲我傳遞數組中的每個字符串。該功能只會對文本進行着色,直到它找到特殊字符(如最終條件中所示),然後爲文本着色。錯誤「NSMutableRLEArray objectAtIndex:effectiveRange ::出界」

代碼:

func formatAttributedString(string:String)->NSMutableAttributedString { 
     var strCopy=string as NSString 
     var color:UIColor=UIColor() 
     var attributedString:NSMutableAttributedString! 

     for var i:Int=0;i<strCopy.length-2;i++ { 
      if (string[i] == "|") { 
       println("|") 
       var j:Int 
       if string[i+1] == "r" { 
        color=UIColor(red: 249, green: 39, blue: 14, alpha: 1) 
        strCopy = strCopy.stringByReplacingOccurrencesOfString("|r", withString: "", options: NSStringCompareOptions.LiteralSearch, range: NSMakeRange(0, i + 2)) 
        println("r") 

       } 
       else if string[i+1] == "v" { 
        color=UIColor(red: 161, green: 153, blue: 249, alpha: 1) 
        strCopy = strCopy.stringByReplacingOccurrencesOfString("|v", withString: "", options: NSStringCompareOptions.LiteralSearch, range: NSMakeRange(0, i + 2)) 
        println("v") 

       } 
       else if string[i+1] == "y" { 
        color=UIColor(red: 235, green: 223, blue: 145, alpha: 1) 
        strCopy = strCopy.stringByReplacingOccurrencesOfString("|y", withString: "", options: NSStringCompareOptions.LiteralSearch, range: NSMakeRange(0, i + 2)) 
        println("y") 
       } 
       else if string[i+1] == "g" { 
        color=UIColor(red: 174, green: 227, blue: 79, alpha: 1) 
        strCopy = strCopy.stringByReplacingOccurrencesOfString("|y", withString: "", options: NSStringCompareOptions.LiteralSearch, range: NSMakeRange(0, i + 2)) 
        println("g") 
       } 
       else if string[i+1] == "b" { 
        color=UIColor(red: 107, green: 224, blue: 240, alpha: 1) 
        strCopy = strCopy.stringByReplacingOccurrencesOfString("|b", withString: "", options: NSStringCompareOptions.LiteralSearch, range: NSMakeRange(0, i + 2)) 
        println("b") 
       } 


       for j=i; j>=0;j-- { 
        if string[j] == " " || string[j] == "/" || string[j] == "." || string[j] == "\"" || string[j] == "\n" || string[j] == "<" || string[j] == "\t" || string[j] == "("{ 
         println("/") 
         break 

        } 
       } 
       attributedString=NSMutableAttributedString(string: strCopy) 
       attributedString.addAttribute("NSForegroundColorAttributeName", value: color, range: NSMakeRange(j, i-j)) 

      } 
     } 

我得到以下錯誤:

'NSMutableRLEArray objectAtIndex:effectiveRange ::越界'

正如我已經加入println小號,|r已打印。 請幫忙,提前致謝。

它不是this question的副本,因爲|r正在打印。

+0

可能重複[NSMutableAttributedStrings - objectAtIndex:effectiveRange ::出界(http://stackoverflow.com/questions/11571948/nsmutableattributedstrings-objectatindexeffectiverange-out-of-bounds) –

+0

你是變異的串隨着你走,改變它的長度,所以你需要在你做替換之後調用'stringByReplacingOccurrencesOfString' – Paulw11

+0

i - 2來減少i。除了for循環最後開始使用超出字符串末尾的索引,因爲您只需縮短它就可以了。 –

回答

1

我試圖通過使用Swift的匿名元組和更高級的函數來滿足您的函數簽名。我爲自己做了一個練習,並最終認爲最好分享。

func formatAttributedString(string: String) -> NSMutableAttributedString { 
    // create a mapping between the attribute token and the corresponding UIColor 
    let colors = [ 
     "|r": UIColor(red: 249/255, green: 39/255, blue: 14/255, alpha: 1.0), 
     "|v": UIColor(red: 161/255, green: 153/255, blue: 249/255, alpha: 1.0), 
     "|y": UIColor(red: 235/255, green: 223/255, blue: 145/255, alpha: 1.0), 
     "|g": UIColor(red: 174/255, green: 227/255, blue: 79/255, alpha: 1.0), 
     "|b": UIColor(red: 107/255, green: 224/255, blue: 240/255, alpha: 1.0)] 

    // split argument into an array of (String, UIColor) tuples 

    // default the array to the entire argument string with a black color 
    var substrings = [(string, UIColor.blackColor())] 

    for (token, color) in colors { 
     substrings = substrings.flatMap { 
      var substrings = $0.0.componentsSeparatedByString(token) 
      let tail = (substrings.removeLast(), $0.1) // tuple for trailing string at old color 
      var result = substrings.map{($0, color)}  // array of tuples for strings at new color 
      result.append(tail) 
      return result 
     } 
    } 
    // because we default the original string to black, there may be an empty string tuple at the end 
    substrings = substrings.filter{(string, _) in return !string.isEmpty} 

    // convert array of (String, UIColor) tuples into a single attributed string 
    var result = reduce(substrings, NSMutableAttributedString(string: "")) { 
     var string = NSAttributedString(string: $1.0, attributes: [NSForegroundColorAttributeName: $1.1]) 
     $0.appendAttributedString(string) 
     return $0 
    } 
    return result 
} 
+0

我收到一個錯誤,說'[String,UIColor]沒有成員名稱flatmap –

+0

flatmap是Swift 1.2的新成員。如果您使用的是最新版本,那麼錯誤表明,子字符串是單個元組,而不是元組數組。 flattop肯定是爲Array類型實現的,但不是匿名元組。僅供參考,這是在我的遊樂場。 –

+0

我剛剛添加了一個擴展並添加了flatMap。我正在調試其他部分,如果它工作,我會接受答案。謝謝!! –

1

我的猜測是在這條線發生的錯誤:

attributedString.addAttribute("NSForegroundColorAttributeName", value: color, range: NSMakeRange(j, i-j))

讓我們來看看你的字符串 「Hello | R世界| G」 - 這是長15個字符。 讓我們看看外層的迭代,找到第二個「|」。 strCopy現在是「Hello World | g」 - 13個字符長,i = 11。 程序找到一個「|」其次是「r」和改變strCopy成的「Hello World | G」 - 11個字符長,我仍然= 11

在內的「掃描」後,我們結束了J = 7

在這條線,你創建的「Hello World」一個可變的字符串:

attributedString=NSMutableAttributedString(string: strCopy)

它,就像strCopy本身,長度等於現在11

,在最後一行,您可以設置屬性範圍內的字符NSRangeMake(7,4),表示t他適用的最後一個字符將位於索引11處。此字符串中的最後一個索引是10,這就是爲什麼您會遇到崩潰。

編輯: 爲了避免這種崩潰,你應該添加「我 - 」;在每行之後用stringByReplacingOccurencesOfString。

另一件事,你也應該這樣做(這將不會導致崩潰,但仍然會使其出現故障是改變內部爲使迴路線路是這樣的:

for j = i + (string.length - strCopy.length); j>=0; j-- {

+0

那麼爲了避免碰撞,我該怎麼做?減少2? –

+0

我編輯了我的答案並添加了一個解決方案。 – johnyu

+0

仍然它creahing。 –

0

你算法似乎取決於指向最後處理的字符的i。每當遇到|?模式時,最終會用「」替換兩個特殊字符,從而有效地將複製字符串大小減少2。

解決問題的最簡單方法是在每次致電strCopy.stringByReplacingOccurrencesOfString...後添加i=i-2

這使i正確的代碼在函數的末尾。

理想情況下,您可能想要考慮重構函數以將項目從原始項目移動到新版本,並隨時添加顏色等。這將保存所有的後向搜索。