我一直在更新我的一些旧代码和答案与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>)

这些一开始让我很困惑,所以我开始摆弄索引和范围。这是子字符串的后续问题和答案。我在下面添加了一个答案来说明它们是如何使用的。


当前回答

斯威夫特5

//假设,需要从2创建子字符串,长度为3

let s = "abcdef"    
let subs = s.suffix(s.count-2).prefix(3) 

// now subs = "cde"

其他回答

String的特殊性在其他答案中已经讨论过了。解释一下:字符串有一个特定的索引,它不是Int类型,因为字符串元素在一般情况下没有相同的大小。因此,String不符合RandomAccessCollection,访问特定索引意味着遍历集合,这不是O(1)操作。

许多答案都提出了使用范围的变通方法,但它们会导致代码效率低下,因为它们使用的String方法(index(from:), index(:offsetBy:),…)不是O(1)。

要像在数组中一样访问字符串元素,您应该使用array:

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

这是一个权衡,数组创建是一个O(n)操作,但数组访问是O(1)。当你想用String(数组)时,你可以转换回String。

我发现了这个相当简单的方法。

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

斯威夫特4

在swift 4字符串符合集合。现在应该使用下标,而不是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与原始字符串共享其存储空间。然而,以这种方式共享内存也很容易导致内存泄漏。

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

let newString = String(result)

你可以在[Apple文档].1中找到更多关于新的Substring类的信息

所以,如果你得到一个范围作为nsregularexexpression的结果,你可以使用以下扩展:

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

}

我的思维很机械。以下是一些基本常识……

斯威夫特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

结果是一个子字符串,这意味着它是原始字符串的一部分。要得到一个完整的独立字符串,只需使用e.g.。

    String(t3)
    String(t4)

这是我所使用的:

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

下面是一个函数,当提供了开始和结束索引时,返回给定子字符串的子字符串。如需完整参考资料,请浏览以下连结。

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
    }
}

这是我为处理swift中的字符串操作而创建的博客文章的链接。 swift中的字符串操作(也包括swift 4)

或者你可以在github上看到这个要点