Substring de uma string em swift | Índice de uma substring em uma string

Eu estou acostumado a fazer isso em JavaScript:

var domains = "abcde".substring(0, "abcde".indexOf("cd")) // Returns "ab" 

O Swift não tem essa function, como fazer algo parecido?

Xcode 9.x • Swift 4.x

 extension StringProtocol where Index == String.Index { func index(of string: T, options: String.CompareOptions = []) -> Index? { return range(of: string, options: options)?.lowerBound } func endIndex(of string: T, options: String.CompareOptions = []) -> Index? { return range(of: string, options: options)?.upperBound } func indexes(of string: T, options: String.CompareOptions = []) -> [Index] { var result: [Index] = [] var start = startIndex while start < endIndex, let range = range(of: string, options: options, range: start..(of string: T, options: String.CompareOptions = []) -> [Range] { var result: [Range] = [] var start = startIndex while start < endIndex, let range = range(of: string, options: options, range: start.. 

uso:

 let str = "abcde" if let index = str.index(of: "cd") { let domains = str.prefix(upTo: index) print(domains) // "ab\n" } 

 let str = "Hello, playground, playground, playground" str.index(of: "play") // 7 str.endIndex(of: "play") // 11 str.indexes(of: "play") // [7, 19, 31] str.ranges(of: "play") // [{lowerBound 7, upperBound 11}, {lowerBound 19, upperBound 23}, {lowerBound 31, upperBound 35}] 

Testado para o Swift 4.1 / 4.0 / 3.0

Usando String[Range] subscrito você pode obter a sub-string. Você precisa iniciar o índice e o último índice para criar o intervalo e você pode fazê-lo como abaixo

 let str = "abcde" if let range = str.range(of: "cd") { let substring = str[.. 

Se você não definir o índice inicial deste operador ..< , ele pega o índice inicial. Você também pode usar str[str.startIndex.. vez de str[..

No Swift 4:

Obtendo o índice de um caractere em uma string:

 let str = "abcdefghabcd" if let index = str.index(of: "b") { print(index) // Index(_compoundOffset: 4, _cache: Swift.String.Index._Cache.character(1)) } 

Criando SubString (prefixo e sufixo) de String usando o Swift 4:

 let str : String = "ilike" for i in 0...str.count { let index = str.index(str.startIndex, offsetBy: i) // String.Index let prefix = str[.. 

Saída

 prefix , suffix : ilike prefix i, suffix : like prefix il, suffix : ike prefix ili, suffix : ke prefix ilik, suffix : e prefix ilike, suffix : 

Se você quiser gerar uma substring entre dois índices, use:

 let substring1 = string[startIndex...endIndex] // including endIndex let subString2 = string[startIndex.. 

Fazer isso no Swift é possível, mas é preciso mais linhas, aqui está uma function indexOf() fazendo o que é esperado:

 func indexOf(source: String, substring: String) -> Int? { let maxIndex = source.characters.count - substring.characters.count for index in 0...maxIndex { let rangeSubstring = source.startIndex.advancedBy(index).. 

Esta function não é otimizada, mas faz o trabalho para strings curtas.

Na versão 3 do Swift, String não tem funções como –

 str.index(of: String) 

Se o índice for necessário para uma substring, uma das maneiras é obter o intervalo. Nós temos as seguintes funções na string que retorna range –

 str.range(of: ) str.rangeOfCharacter(from: ) str.range(of: , options: , range: ?>, locale: ) 

Por exemplo, para encontrar os índices da primeira ocorrência de jogo em str

 var str = "play play play" var range = str.range(of: "play") range?.lowerBound //Result : 0 range?.upperBound //Result : 4 

Nota: o intervalo é opcional. Se não for capaz de encontrar a String, ela será nula. Por exemplo

 var str = "play play play" var range = str.range(of: "zoo") //Result : nil range?.lowerBound //Result : nil range?.upperBound //Result : nil 

Há três problemas intimamente conectados aqui:

  • Todos os methods de localização de substring terminaram no mundo do NSString de cocoa (Foundation)

  • O Foundation NSRange tem uma incompatibilidade com o Swift Range; o primeiro usa início e comprimento, o último usa terminais

  • Em geral, os caracteres Swift são indexados usando String.Index , não Int, mas os caracteres Foundation são indexados usando Int, e não há tradução direta simples entre eles (porque Foundation e Swift têm idéias diferentes do que constitui um caractere)

Dado tudo isso, vamos pensar em como escrever:

 func substring(of s: String, from:Int, toSubstring s2 : String) -> Substring? { // ? } 

A substring s2 deve ser procurada em s usando um método String Foundation. O intervalo resultante retorna para nós, não como um NSRange (embora este seja um método Foundation), mas como um Range of String.Index (empacotado em um opcional, caso não tenhamos encontrado a substring). No entanto, o outro número, from , é um Int. Assim, não podemos formar qualquer tipo de alcance envolvendo os dois.

Mas nós não precisamos! Tudo o que precisamos fazer é cortar o final da string original usando um método que use String.Index e cortar o início da string original usando um método que use Int. Felizmente, esses methods existem! Como isso:

 func substring(of s: String, from:Int, toSubstring s2 : String) -> Substring? { guard let r = s.range(of:s2) else {return nil} var s = s.prefix(upTo:r.lowerBound) s = s.dropFirst(from) return s } 

Ou, se preferir poder aplicar este método diretamente a uma string, como esta …

 let output = "abcde".substring(from:0, toSubstring:"cd") 

… então faça uma extensão em String:

 extension String { func substring(from:Int, toSubstring s2 : String) -> Substring? { guard let r = self.range(of:s2) else {return nil} var s = self.prefix(upTo:r.lowerBound) s = s.dropFirst(from) return s } }