【问题标题】:How does String substring work in Swift字符串子字符串在 Swift 中是如何工作的
【发布时间】:2017-02-02 06:59:51
【问题描述】:

我一直在使用 Swift 3 更新我的一些旧代码和答案,但是当我使用 Swift 字符串和使用子字符串进行索引时,事情变得令人困惑。

具体来说,我正在尝试以下方法:

let str = "Hello, playground"
let prefixRange = str.startIndex..<str.startIndex.advancedBy(5)
let prefix = str.substringWithRange(prefixRange)

第二行给了我以下错误

'String' 类型的值没有成员 'substringWithRange'

我看到String 现在确实有以下方法:

str.substring(to: String.Index)
str.substring(from: String.Index)
str.substring(with: Range<String.Index>)

一开始我真的很困惑,所以我开始玩index and range。这是子字符串的后续问题和答案。我在下面添加一个答案来说明它们是如何使用的。

【问题讨论】:

标签: swift string range substring


【解决方案1】:

以下所有示例都使用

var str = "Hello, playground"

斯威夫特 4

Strings 在 Swift 4 中得到了相当大的改进。当你现在从 String 中获取一些子字符串时,你会得到一个 Substring 类型,而不是 String。为什么是这样?字符串是 Swift 中的值类型。这意味着如果您使用一个字符串来创建一个新字符串,则必须将其复制过来。这有利于稳定性(没有其他人会在你不知情的情况下更改它)但不利于效率。

另一方面,子字符串是对其来源的原始字符串的引用。这是来自documentation 的图片说明了这一点。

无需复制,因此使用效率更高。但是,假设您从一百万个字符的字符串中得到了一个十字符的子字符串。因为 Substring 正在引用 String,所以只要 Substring 存在,系统就必须保留整个 String。因此,每当您完成对子字符串的操作时,请将其转换为字符串。

let myString = String(mySubstring)

这将只复制子字符串,保存旧字符串的内存可以是reclaimed。子字符串(作为一种类型)是短暂的。

Swift 4 的另一个重大改进是字符串是集合(再次)。这意味着您可以对集合执行任何操作,也可以对字符串执行任何操作(使用下标、迭代字符、过滤器等)。

以下示例展示了如何在 Swift 中获取子字符串。

获取子字符串

您可以使用下标或许多其他方法(例如,prefixsuffixsplit)从字符串中获取子字符串。不过,您仍然需要使用String.Index 而不是Int 范围索引。 (如果您需要帮助,请参阅 my other answer。)

字符串的开头

您可以使用下标(注意 Swift 4 单边范围):

let index = str.index(str.startIndex, offsetBy: 5)
let mySubstring = str[..<index] // Hello

prefix:

let index = str.index(str.startIndex, offsetBy: 5)
let mySubstring = str.prefix(upTo: index) // Hello

甚至更简单:

let mySubstring = str.prefix(5) // Hello

字符串结束

使用下标:

let index = str.index(str.endIndex, offsetBy: -10)
let mySubstring = str[index...] // playground

suffix:

let index = str.index(str.endIndex, offsetBy: -10)
let mySubstring = str.suffix(from: index) // playground

甚至更简单:

let mySubstring = str.suffix(10) // playground

请注意,当使用suffix(from: index) 时,我必须使用-10 从末尾倒数。仅使用 suffix(x) 时没有必要这样做,它只使用字符串的最后一个 x 字符。

字符串中的范围

我们再次在这里简单地使用下标。

let start = str.index(str.startIndex, offsetBy: 7)
let end = str.index(str.endIndex, offsetBy: -6)
let range = start..<end

let mySubstring = str[range]  // play

Substring 转换为String

别忘了,当你准备好保存你的子字符串时,你应该把它转换成String,这样旧字符串的内存就可以被清理掉了。

let myString = String(mySubstring)

使用Int 索引扩展?

在阅读了 Airspeed Velocity 和 Ole Begemann 的文章 Strings in Swift 3 后,我犹豫是否要使用基于 Int 的索引扩展。尽管在 Swift 4 中,字符串是集合,但 Swift 团队故意没有使用 Int 索引。它仍然是String.Index。这与由不同数量的 Unicode 代码点组成的 Swift 字符有关。必须为每个字符串唯一地计算实际索引。

我不得不说,我希望 Swift 团队在未来能找到一种方法来抽象出 String.Index。但在他们之前,我选择使用他们的 API。它帮助我记住字符串操作不仅仅是简单的Int 索引查找。

【讨论】:

  • 感谢您的描述。当之无愧的升级。苹果把这件事复杂化了。子字符串应该像 string.substring[from...to] 一样简单。
  • 很好的解释。除了一件小事garbage collected ;-) 我希望这里的人们知道 Swift 中没有垃圾收集。
  • @ChristianAnchorDampf,感谢您抽出宝贵时间发表评论。我拿出垃圾收集器。新措辞如何?
  • 说得好!谢谢你的解释。
  • 感谢详细的解释!完全同意@Teddy - unicode 宽度应该是实现细节,因为大多数人并不关心字节的实际外观。 API 设计应该是 95% 左右的用例,并为需要处理协议栈等的人提供低级 API。
【解决方案2】:

我对 Swift 的字符串访问模型感到非常沮丧:一切都必须是 Index。我想要的只是使用Int 访问字符串的第 i 个字符,而不是笨拙的索引和前进(每个主要版本都会改​​变)。于是我就扩展了String

extension String {
    func index(from: Int) -> Index {
        return self.index(startIndex, offsetBy: from)
    }

    func substring(from: Int) -> String {
        let fromIndex = index(from: from)
        return String(self[fromIndex...])
    }

    func substring(to: Int) -> String {
        let toIndex = index(from: to)
        return String(self[..<toIndex])
    }

    func substring(with r: Range<Int>) -> String {
        let startIndex = index(from: r.lowerBound)
        let endIndex = index(from: r.upperBound)
        return String(self[startIndex..<endIndex])
    }
}

let str = "Hello, playground"
print(str.substring(from: 7))         // playground
print(str.substring(to: 5))           // Hello
print(str.substring(with: 7..<11))    // play

【讨论】:

  • 索引非常有用,因为一个字符可以超过一个字节。试试let str = "??????Hello"print(str.substring(to: 2))
  • 是的,我知道一个字符(即扩展字形簇)可以占用多个字节。我的沮丧是为什么我们必须使用详细的索引推进方法来访问字符串的字符。为什么 Swift 团队不能在核心库中添加一些重载来抽象它。如果我键入str[5],我想访问索引 5 处的字符,无论该字符看起来是什么或它需要多少字节。 Swift 不就是为了提高开发人员的生产力吗?
  • @RenniePet 我相信 Apple 意识到了这个问题,并且即将做出改变。根据 GitHub 上的 Swift Evolution 页面:“Swift 4 旨在使字符串更强大、更易于使用,同时默认保留 Unicode 正确性”。这很模糊,但让我们保持希望
  • @CodeDifferent 为什么苹果没有添加下标字符访问?让人们明白这是一件坏事。基本上,如果您使用双循环的下标为 i in 0..string.count 执行操作,则导致引擎盖下的索引必须遍历字符串的每个字节才能找出下一个字符。如果使用索引进行循环,则仅对字符串进行一次迭代。顺便说一句,我自己讨厌这个,但这就是下标在 swift 中无法在字符串上使用的原因。
  • @RaimundasSakalauskas 这个论点并没有被我忽略。 C# 既有 Unicode 正确性,又有整数下标,真的很方便。在 Swift 1 中,Apple 希望开发人员使用 countElement(str) 来查找长度。在 Swift 3 中,Apple 使字符串不符合 Sequence 并强制所有人改用 str.characters。这些家伙不怕做出改变。他们对整数下标的固执真的很难理解
【解决方案3】:

我最初的反应是一样的。我也对每个主要版本的语法和对象变化如此之大感到沮丧。

但是,我从经验中意识到,我最终总是要承受试图与“改变”作斗争的后果,比如处理多字节字符,如果你着眼于全球观众,这是不可避免的。

因此,我决定认可并尊重 Apple 工程师所做的努力,并通过了解他们提出这种“可怕”方法时的心态来尽自己的一份力量。

与其创建只是让您的生活更轻松的解决方法的扩展(我并不是说它们是错误的或昂贵的),不如弄清楚字符串现在是如何设计的。

例如,我有这段代码在 Swift 2.2 上运行:

let rString = cString.substringToIndex(2)
let gString = (cString.substringFromIndex(2) as NSString).substringToIndex(2)
let bString = (cString.substringFromIndex(4) as NSString).substringToIndex(2)

在放弃尝试使用相同的方法后,例如使用子字符串,我终于理解了将字符串视为双向集合的概念,我最终得到了相同代码的这个版本:

let rString = String(cString.characters.prefix(2))
cString = String(cString.characters.dropFirst(2))
let gString = String(cString.characters.prefix(2))
cString = String(cString.characters.dropFirst(2))
let bString = String(cString.characters.prefix(2))

我希望这有助于...

【讨论】:

  • 好吧,处理一个复杂的问题并不意味着解决方案可以很优雅。同样,我也理解这个问题,但是整个 String 类和处理它真是太可怕了。
【解决方案4】:

同样的挫败感,这不应该那么难......

我编译了这个从大文本中获取子字符串位置的示例:

//
// Play with finding substrings returning an array of the non-unique words and positions in text
//
//

import UIKit

let Bigstring = "Why is it so hard to find substrings in Swift3"
let searchStrs : Array<String>? = ["Why", "substrings", "Swift3"]

FindSubString(inputStr: Bigstring, subStrings: searchStrs)


func FindSubString(inputStr : String, subStrings: Array<String>?) ->    Array<(String, Int, Int)> {
    var resultArray : Array<(String, Int, Int)> = []
    for i: Int in 0...(subStrings?.count)!-1 {
        if inputStr.contains((subStrings?[i])!) {
            let range: Range<String.Index> = inputStr.range(of: subStrings![i])!
            let lPos = inputStr.distance(from: inputStr.startIndex, to: range.lowerBound)
            let uPos = inputStr.distance(from: inputStr.startIndex, to: range.upperBound)
            let element = ((subStrings?[i])! as String, lPos, uPos)
            resultArray.append(element)
        }
    }
    for words in resultArray {
        print(words)
    }
    return resultArray
}

返回 (“为什么”, 0, 3) ("子串", 26, 36) ("Swift3", 40, 46)

【讨论】:

  • 那是一些代码,但并没有真正解释字符串索引和子字符串在 swift3 中是如何工作的。
【解决方案5】:

我是 Swift 3 的新手,但在查看 String (index) 语法进行类比时,我认为 index 就像一个限制为字符串的“指针”,而 Int 可以作为一个独立的对象提供帮助。使用 base + offset 语法,然后我们可以使用下面的代码从字符串中获取第 i 个字符:

let s = "abcdefghi"
let i = 2
print (s[s.index(s.startIndex, offsetBy:i)])
// print c

对于使用字符串(范围)语法的字符串中的一系列字符(索引),我们可以使用下面的代码获得第 i 个到第 f 个字符:

let f = 6
print (s[s.index(s.startIndex, offsetBy:i )..<s.index(s.startIndex, offsetBy:f+1 )])
//print cdefg

对于使用 String.substring (range) 的字符串中的子字符串(范围),我们可以使用下面的代码获取子字符串:

print (s.substring (with:s.index(s.startIndex, offsetBy:i )..<s.index(s.startIndex, offsetBy:f+1 ) ) )
//print cdefg

注意事项:

  1. 第i个和第f个以0开头。

  2. 到f-th,我用offsetBY:f + 1,因为订阅范围使用..

  3. 当然必须包括无效索引等验证错误。

【讨论】:

    【解决方案6】:

    我为此创建了一个简单的扩展 (Swift 3)

    extension String {
        func substring(location: Int, length: Int) -> String? {
            guard characters.count >= location + length else { return nil }
            let start = index(startIndex, offsetBy: location)
            let end = index(startIndex, offsetBy: location + length)
            return substring(with: start..<end)
        }
    }
    

    【讨论】:

      【解决方案7】:

      这是一个函数,它在提供开始和结束索引时返回给定子字符串的子字符串。如需完整参考,您可以访问下面给出的链接。

      func substring(string: String, fromIndex: Int, toIndex: Int) -> String? {
          if fromIndex < toIndex && toIndex < string.count /*use string.characters.count for swift3*/{
              let startIndex = string.index(string.startIndex, offsetBy: fromIndex)
              let endIndex = string.index(string.startIndex, offsetBy: toIndex)
              return String(string[startIndex..<endIndex])
          }else{
              return nil
          }
      }
      

      这是我为快速处理字符串操作而创建的博客文章的链接。 String manipulation in swift (Covers swift 4 as well)

      Or you can see this gist on github

      【讨论】:

        【解决方案8】:

        Swift 5 扩展:

        extension String {
            subscript(_ range: CountableRange<Int>) -> String {
                let start = index(startIndex, offsetBy: max(0, range.lowerBound))
                let end = index(start, offsetBy: min(self.count - range.lowerBound, 
                                                     range.upperBound - range.lowerBound))
                return String(self[start..<end])
            }
        
            subscript(_ range: CountablePartialRangeFrom<Int>) -> String {
                let start = index(startIndex, offsetBy: max(0, range.lowerBound))
                 return String(self[start...])
            }
        }
        

        用法:

        let s = "hello"
        s[0..<3] // "hel"
        s[3...]  // "lo"
        

        或unicode:

        let s = "???"
        s[0..<1] // "?"
        

        【讨论】:

        • 好多了,感谢您发布此扩展程序!我认为来自 Python 的 Swift 比习惯要困难得多。对于从 Objective C 到 Swift 的另一个方向的人来说,似乎有更积极的确认。
        • @Leon 我刚刚删除了它。在 4.1 之前,count 仅在 self.characters 上可用
        • 这个特定的扩展有什么需要注意的地方吗?苹果为什么不做这样的事情?
        • 如果你想写例如你还需要添加an extension that takes a CountableClosedRange&lt;Int&gt; s[0...2].
        • @ChrisFrederick 和 CountablePartialRangeFrom&lt;Int&gt; 为 s[2...]。
        【解决方案9】:

        斯威夫特 4

        在 swift 4 中,String 符合 Collection。我们现在应该使用subscript. 而不是substring,所以如果您只想从"Hello, playground" 中删除单词"play",您可以这样做:

        var str = "Hello, playground"
        let start = str.index(str.startIndex, offsetBy: 7)
        let end = str.index(str.endIndex, offsetBy: -6)
        let result = str[start..<end] // The result is of type Substring
        

        有趣的是,这样做会给你一个Substring 而不是String。这是快速高效的,因为Substring 与原始字符串共享其存储空间。但是,以这种方式共享内存也很容易导致内存泄漏。

        这就是为什么你应该将结果复制到一个新的字符串中,一旦你想清理原始字符串。你可以使用普通的构造函数来做到这一点:

        let newString = String(result)
        

        您可以在 [Apple 文档] 中找到有关新 Substring 类的更多信息。1

        因此,例如,如果您得到 Range 作为 NSRegularExpression 的结果,您可以使用以下扩展名:

        extension String {
        
            subscript(_ range: NSRange) -> String {
                let start = self.index(self.startIndex, offsetBy: range.lowerBound)
                let end = self.index(self.startIndex, offsetBy: range.upperBound)
                let subString = self[start..<end]
                return String(subString)
            }
        
        }
        

        【讨论】:

        • 如果 range.upperBound 为 > 字符串长度,您的代码将崩溃。此外,示例用法也会有所帮助,因为我不熟悉 Swift 中的下标。您可以包含类似 datePartOnly = "2018-01-04-08:00"[NSMakeRange(0, 10)] 的内容。除此之外,非常好的答案,+1 :)。
        • 现在这很奇怪:text[Range( nsRange , in: text)!]
        【解决方案10】:

        斯威夫特 4

        extension String {
            subscript(_ i: Int) -> String {
                let idx1 = index(startIndex, offsetBy: i)
                let idx2 = index(idx1, offsetBy: 1)
                return String(self[idx1..<idx2])
            }
        }
        
        let s = "hello"
        
        s[0]    // h
        s[1]    // e
        s[2]    // l
        s[3]    // l
        s[4]    // o
        

        【讨论】:

        • 现在用一百万个字符的字符串试试这个。
        • 为什么?会发生什么?
        【解决方案11】:

        斯威夫特 4

        “子字符串”(https://developer.apple.com/documentation/swift/substring):

        let greeting = "Hi there! It's nice to meet you! ?"
        let endOfSentence = greeting.index(of: "!")!
        let firstSentence = greeting[...endOfSentence]
        // firstSentence == "Hi there!"
        

        扩展字符串示例:

        private typealias HowDoYouLikeThatElonMusk = String
        private extension HowDoYouLikeThatElonMusk {
        
            subscript(_ from: Character?, _ to: Character?, _ include: Bool) -> String? {
                if let _from: Character = from, let _to: Character = to {
                    let dynamicSourceForEnd: String = (_from == _to ? String(self.reversed()) : self)
                    guard let startOfSentence: String.Index = self.index(of: _from),
                        let endOfSentence: String.Index = dynamicSourceForEnd.index(of: _to) else {
                        return nil
                    }
        
                    let result: String = String(self[startOfSentence...endOfSentence])
                    if include == false {
                        guard result.count > 2 else {
                                return nil
                        }
                        return String(result[result.index(result.startIndex, offsetBy: 1)..<result.index(result.endIndex, offsetBy: -1)])
                    }
                    return result
                } else if let _from: Character = from {
                    guard let startOfSentence: String.Index = self.index(of: _from) else {
                        return nil
                    }
                    let result: String = String(self[startOfSentence...])
                    if include == false {
                        guard result.count > 1 else {
                            return nil
                        }
                        return String(result[result.index(result.startIndex, offsetBy: 1)...])
                    }
                    return result
                } else if let _to: Character = to {
                    guard let endOfSentence: String.Index = self.index(of: _to) else {
                            return nil
                    }
                    let result: String = String(self[...endOfSentence])
                    if include == false {
                        guard result.count > 1 else {
                            return nil
                        }
                        return String(result[..<result.index(result.endIndex, offsetBy: -1)])
                    }
                    return result
                }
                return nil
            }
        }
        

        使用扩展字符串的例子:

        let source =                                   ">>>01234..56789<<<"
        // include = true
        var from =          source["3", nil, true]  //       "34..56789<<<"
        var to =            source[nil, "6", true]  // ">>>01234..56"
        var fromTo =        source["3", "6", true]  //       "34..56"
        let notFound =      source["a", nil, true]  // nil
        // include = false
        from =              source["3", nil, false] //        "4..56789<<<"
        to =                source[nil, "6", false] // ">>>01234..5"
        fromTo =            source["3", "6", false] //        "4..5"
        let outOfBounds =   source[".", ".", false] // nil
        
        let str = "Hello, playground"
        let hello = str[nil, ",", false] // "Hello"
        

        【讨论】:

          【解决方案12】:

          这是一个更通用的实现:

          这种技术仍然使用index 以符合 Swift 的标准,并暗示一个完整的字符。

          extension String
          {
              func subString <R> (_ range: R) -> String? where R : RangeExpression, String.Index == R.Bound
              {
                  return String(self[range])
              }
          
              func index(at: Int) -> Index
              {
                  return self.index(self.startIndex, offsetBy: at)
              }
          }
          

          到第三个字符的子字符串:

          let item = "Fred looks funny"
          item.subString(item.index(at: 2)...) // "ed looks funny"
          

          我使用骆驼subString 表示它返回String 而不是Substring

          【讨论】:

            【解决方案13】:

            在上面的基础上,我需要在一个非打印字符处拆分一个字符串,删除非打印字符。我开发了两种方法:

            var str = "abc\u{1A}12345sdf"
            let range1: Range<String.Index> = str.range(of: "\u{1A}")!
            let index1: Int = str.distance(from: str.startIndex, to: range1.lowerBound)
            let start = str.index(str.startIndex, offsetBy: index1)
            let end = str.index(str.endIndex, offsetBy: -0)
            let result = str[start..<end] // The result is of type Substring
            let firstStr = str[str.startIndex..<range1.lowerBound]
            

            我使用上面的一些答案放在一起。

            因为 String 是一个集合,所以我做了以下操作:

            var fString = String()
            for (n,c) in str.enumerated(){
            
            *if c == "\u{1A}" {
                print(fString);
                let lString = str.dropFirst(n + 1)
                print(lString)
                break
               }
             fString += String(c)
            }*
            

            这对我来说更直观。哪个最好?我没有办法告诉 他们都使用 Swift 5

            【讨论】:

            • 感谢您的回答。 Swift 5 中的字符串有什么不同吗?我还没有时间玩它。
            • 他们这么说,但我还没有机会去调查。
            【解决方案14】:

            我的思维很机械。以下是基础知识...

            斯威夫特 4 斯威夫特 5

              let t = "abracadabra"
            
              let start1 = t.index(t.startIndex, offsetBy:0)
              let   end1 = t.index(t.endIndex, offsetBy:-5)
              let start2 = t.index(t.endIndex, offsetBy:-5)
              let   end2 = t.index(t.endIndex, offsetBy:0)
            
              let t2 = t[start1 ..< end1]
              let t3 = t[start2 ..< end2]                
            
              //or a shorter form 
            
              let t4 = t[..<end1]
              let t5 = t[start2...]
            
              print("\(t2) \(t3) \(t)")
              print("\(t4) \(t5) \(t)")
            
              // result:
              // abraca dabra abracadabra
            

            结果是一个子字符串,这意味着它是原始字符串的一部分。要获得完整的单独字符串,只需使用例如

                String(t3)
                String(t4)
            

            这是我用的:

                let mid = t.index(t.endIndex, offsetBy:-5)
                let firstHalf = t[..<mid]
                let secondHalf = t[mid...]
            

            【讨论】:

              【解决方案15】:

              Swift 4+

              extension String {
                  func take(_ n: Int) -> String {
                      guard n >= 0 else {
                          fatalError("n should never negative")
                      }
                      let index = self.index(self.startIndex, offsetBy: min(n, self.count))
                      return String(self[..<index])
                  }
              }
              

              返回前 n 个字符的子序列,如果字符串较短,则返回整个字符串。 (灵感来自:https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/take.html

              例子:

              let text = "Hello, World!"
              let substring = text.take(5) //Hello
              

              【讨论】:

                【解决方案16】:

                Swift 4 和 5:

                extension String {
                  subscript(_ i: Int) -> String {
                    let idx1 = index(startIndex, offsetBy: i)
                    let idx2 = index(idx1, offsetBy: 1)
                    return String(self[idx1..<idx2])
                  }
                
                  subscript (r: Range<Int>) -> String {
                    let start = index(startIndex, offsetBy: r.lowerBound)
                    let end = index(startIndex, offsetBy: r.upperBound)
                    return String(self[start ..< end])
                  }
                
                  subscript (r: CountableClosedRange<Int>) -> String {
                    let startIndex =  self.index(self.startIndex, offsetBy: r.lowerBound)
                    let endIndex = self.index(startIndex, offsetBy: r.upperBound - r.lowerBound)
                    return String(self[startIndex...endIndex])
                  }
                }
                

                使用方法:

                "abcde"[0] --> "a"

                "abcde"[0...2] --> "abc"

                "abcde"[2.. "cd"

                【讨论】:

                  【解决方案17】:

                  Swift 5
                  let desiredIndex: Int = 7 let substring = str[String.Index(encodedOffset: desiredIndex)...]
                  这个子字符串变量会给你结果。
                  只需在这里将 Int 转换为 Index ,然后您就可以拆分字符串。除非你会出错。

                  【讨论】:

                  • 这是错误的。一个字符可能由一个或多个字节组成。它仅适用于 ascii 文本。
                  【解决方案18】:

                  遇到了这种相当短且简单的方法来实现这一点。

                  var str = "Hello, World"
                  let arrStr = Array(str)
                  print(arrStr[0..<5]) //["H", "e", "l", "l", "o"]
                  print(arrStr[7..<12]) //["W", "o", "r", "l", "d"]
                  print(String(arrStr[0..<5])) //Hello
                  print(String(arrStr[7..<12])) //World
                  

                  【讨论】:

                    【解决方案19】:

                    String 的特殊性主要在其他答案中得到解决。解释一下:String 有一个特定的Index,它不是Int 类型,因为在一般情况下字符串元素的大小不同。因此,String 不符合 RandomAccessCollection 并且访问特定索引意味着遍历集合,这不是 O(1) 操作。

                    许多答案都提出了使用范围的解决方法,但它们可能会导致代码效率低下,因为它们使用不是 O(1) 的字符串方法(index(from:)index(:offsetBy:)、...)。

                    要访问数组中的字符串元素,您应该使用Array

                    let array = Array("Hello, world!")
                    let letter = array[5]
                    

                    这是一个权衡,创建数组是一个 O(n) 操作,但数组访问是 O(1)。您可以随时使用String(array) 转换回字符串。

                    【讨论】:

                    • 如果您正在处理自己的文本,这似乎是一个不错的选择。但是,如果它来自用户,您会遇到代理对和字素集群的问题。
                    • 当然,这应该谨慎使用,用户必须知道他在做什么。
                    【解决方案20】:
                    var str = "VEGANISM"
                    print (str[str.index(str.startIndex, offsetBy:2)..<str.index(str.endIndex, offsetBy: -1)] )
                    
                    //Output-> GANIS
                    

                    这里,str.startIndexstr.endIndex 是字符串的起始索引和结束索引。

                    这里作为 startIndex = 2 -> str.index(str.startIndex, offsetBy:2) 中的 offsetBy ,因此修剪后的字符串将从索引 2 开始(即从第二个字符开始)和 endIndex = -1 中的 offsetBy -> str.index(str.endIndex, offsetBy: -1) 即正在修剪 1 个字符从头到尾。

                    var str = "VEGANISM"
                    print (str[str.index(str.startIndex, offsetBy:0)..<str.index(str.endIndex, offsetBy: 0)] )
                    
                    //Output-> VEGANISM
                    

                    由于两边都是offsetBy value = 0,即str.index(str.startIndex, offsetBy:0)str.index(str.endIndex, offsetBy: 0),因此正在打印完整的字符串

                    【讨论】:

                      【解决方案21】:

                      我创建了一个这样的简单函数:

                      func sliceString(str: String, start: Int, end: Int) -> String {
                          let data = Array(str)
                          return String(data[start..<end])
                      }
                      

                      你可以通过以下方式使用它

                      print(sliceString(str: "0123456789", start: 0, end: 3)) // -> prints 012
                      

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2021-04-16
                        • 1970-01-01
                        • 2018-10-13
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多