Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
字符串子字符串在Swift中是如何工作的_Swift_String_Range_Substring - Fatal编程技术网

字符串子字符串在Swift中是如何工作的

字符串子字符串在Swift中是如何工作的,swift,string,range,substring,Swift,String,Range,Substring,我一直在用Swift 3更新我的一些旧代码和答案,但是当我使用Swift字符串和子字符串进行索引时,事情变得很混乱 具体而言,我尝试了以下几点: let str = "Hello, playground" let prefixRange = str.startIndex..<str.startIndex.advancedBy(5) let prefix = str.substringWithRange(prefixRange) String(t3) String(t4)

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

具体而言,我尝试了以下几点:

let str = "Hello, playground"
let prefixRange = str.startIndex..<str.startIndex.advancedBy(5)
let prefix = str.substringWithRange(prefixRange)
    String(t3)
    String(t4)
一开始我真的很困惑,所以我开始到处玩。这是子字符串的后续问题和答案。我在下面添加了一个答案来说明它们是如何使用的。

以下所有示例都使用

var str = "Hello, playground"
斯威夫特4 弦乐在《斯威夫特4》中得到了相当大的改进。当您现在从字符串中获得一些子字符串时,您会得到一个
子字符串
而不是
字符串
。为什么会这样?字符串是Swift中的值类型。这意味着,如果您使用一个字符串来创建一个新字符串,则必须将其复制过来。这有利于稳定性(没有人会在你不知情的情况下改变它),但不利于效率

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

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

let myString = String(mySubstring)
这将只复制子字符串,并且可以复制保存旧字符串的内存。子字符串(作为一种类型)的寿命很短

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

以下示例演示如何在Swift中获取子字符串

获取子字符串 您可以使用下标或许多其他方法(例如,
前缀
后缀
拆分
)从字符串中获取子字符串。不过,您仍然需要使用
String.Index
,而不是范围的
Int
索引。(看看你是否需要帮助。)

字符串的开头 您可以使用下标(注意Swift 4单边范围):

甚至更简单:

let mySubstring = str.prefix(5) // Hello
let mySubstring = str.suffix(10) // playground
弦外之音 使用下标:

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

let index = str.index(str.startIndex, offsetBy: 5)
let mySubstring = str.prefix(upTo: index) // Hello
let index = str.index(str.endIndex, offsetBy: -10)
let mySubstring = str.suffix(from: index) // playground
甚至更简单:

let mySubstring = str.prefix(5) // Hello
let mySubstring = str.suffix(10) // playground
注意,当使用
后缀(from:index)
时,我必须使用
-10
从末尾倒数。当只使用后缀(x)时,这是不必要的,它只接受字符串的最后一个
x
字符

let myString = String(mySubstring)
字符串中的范围 同样,我们在这里只使用下标

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
使用
Int
索引扩展名? 在阅读了空速和奥勒·贝格曼的文章之后,我很犹豫是否使用基于
Int
的索引扩展。尽管在Swift 4中,字符串是集合,但Swift团队故意没有使用
Int
索引。它仍然是
String.Index
。这与由不同数量的Unicode代码点组成的Swift字符有关。必须为每个字符串唯一地计算实际索引


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

我对斯威夫特的字符串访问模型非常失望:所有东西都必须是
索引。我只想使用
Int
访问字符串的第I个字符,而不是笨拙的索引和前进(每一个主要版本都会发生变化)。因此,我对
字符串进行了扩展:

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
扩展字符串{
func索引(from:Int)->index{
返回自索引(起始索引,抵销人:起始)
}
func子字符串(from:Int)->字符串{
let fromIndex=索引(from:from)
返回字符串(self[fromIndex…])
}
func子字符串(to:Int)->字符串{
让toIndex=索引(从:到)
返回字符串(self[…字符串{
让startIndex=索引(起始:r.lowerBound)
让endIndex=index(from:r.upperBound)

返回字符串(self[startIndex..我也有同样的最初反应。我也对语法和对象在每个主要版本中的变化如此剧烈感到沮丧

然而,我从经验中认识到,我总是会最终承受与“变化”抗争的后果,就像处理多字节字符一样,如果你面对的是全球受众,这是不可避免的

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

与其创建只是让您的生活更轻松的变通方法的扩展(我不是说它们是错误的或昂贵的),为什么不弄清楚字符串现在是如何工作的呢

例如,我有一个在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))

我希望这有助于…

同样的沮丧,这不应该那么难

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

//
// 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
}
//
//尝试查找返回文本中非唯一单词和位置数组的子字符串
//
//
导入UIKit
let Bigstring=“为什么在Swift3中很难找到子字符串”
让searchStrs:Array?=[“为什么”,“子字符串”,“Swift3”]
FindSubString(inputStr:Bigstring,SubString:searchStrs)
func FindSubString(inputStr:String,substring:Array?->Array{
var resultArray:Array=[]
对于i:0中的Int…(子字符串?.count)!-1{
如果inputStr.包含((子字符串?[i])!)
let f = 6
print (s[s.index(s.startIndex, offsetBy:i )..<s.index(s.startIndex, offsetBy:f+1 )])
//print cdefg
print (s.substring (with:s.index(s.startIndex, offsetBy:i )..<s.index(s.startIndex, offsetBy:f+1 ) ) )
//print cdefg
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)
    }
}
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
    }
}
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"
let s = "

Swift 4

In swift 4
String
conforms to
Collection
. Instead of
substring
, we should now use a
subscript.
So if you want to cut out only the word
"play"
from
"Hello, playground"
, you could do it like this:

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
let newString = String(result)
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)
    }

}
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
let greeting = "Hi there! It's nice to meet you! Heres a more generic implementation:

This technique still uses
index
to keep with Swift's standards, and imply a full Character.

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"
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]
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)
}*
  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...]
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])
    }
}
let text = "Hello, World!"
let substring = text.take(5) //Hello
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])
  }
}
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
var str = "VEGANISM"
print (str[str.index(str.startIndex, offsetBy:2)..<str.index(str.endIndex, offsetBy: -1)] )

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

//Output-> VEGANISM