Ainda não consegui descobrir como obter uma substring de a String
no Swift:
var str = “Hello, playground”
func test(str: String) -> String {
return str.substringWithRange( /* What goes here? */ )
}
test (str)
Não consigo criar um intervalo no Swift. O preenchimento automático no Playground não é muito útil - é o que sugere:
return str.substringWithRange(aRange: Range<String.Index>)
Não encontrei nada na Swift Standard Reference Library que ajude. Aqui estava outro palpite:
return str.substringWithRange(Range(0, 1))
E isto:
let r:Range<String.Index> = Range<String.Index>(start: 0, end: 2)
return str.substringWithRange(r)
Eu já vi outras respostas ( Encontrar índice de caracteres no Swift String ) que parecem sugerir que, como String
é um tipo de ponte NSString
, os métodos "antigos" devem funcionar, mas não está claro como - por exemplo, isso também não funciona ( parece não ser uma sintaxe válida):
let x = str.substringWithRange(NSMakeRange(0, 3))
Pensamentos?
Respostas:
Você pode usar o método substringWithRange. É preciso um início e um fim String.Index.
Para alterar o índice inicial e final, use advancedBy (n).
Você também ainda pode usar o método NSString com o NSRange, mas precisa verificar se está usando um NSString como este:
Nota: como o JanX2 mencionou, este segundo método não é seguro com strings unicode.
fonte
advance
significa que precisamos percorrer todo o caminho através de uma sequência possivelmente longa. Mas formar um NSRange e usar o NSString explicitamente é perigoso? O que sobrou?Swift 2
Simples
Swift 3
Swift 4
substring(to:)
esubstring(from:)
estão obsoletosSwift 4
.fonte
NOTA: O @airspeedswift faz alguns pontos muito esclarecedores sobre as compensações dessa abordagem, particularmente os impactos ocultos no desempenho. Strings não são bestas simples, e chegar a um índice específico pode levar O (n) tempo, o que significa que um loop que usa um subscrito pode ser O (n ^ 2). Você foi avisado.
Você só precisa adicionar uma nova
subscript
função que tenha um intervalo e useadvancedBy()
para ir até onde você deseja:(Definitivamente, isso deve fazer parte do idioma. Dupe rdar: // 17158813 )Por diversão, você também pode adicionar um
+
operador aos índices:(Ainda não sei se este deve fazer parte do idioma ou não.)
fonte
advance<T>(…)
noSwift
espaço para nome.String.Index
. Nesse caso, não é tanto a otimização, mas mantém tudo direto. Ter que fazer malabarismos entre int e String.Index para frente e para trás em todos os lugares leva a uma confusão.String.Index
es), o que geralmente acontece. Então você pode apenas desejar que todos os métodos de manipulação de strings estejam trabalhando comInt
s. E você é forçado a convertê-lo para oString.Indexes
que leva à bagunça que você mencionou.No momento em que estou escrevendo, nenhuma extensão é perfeitamente compatível com o Swift 4.2 , então aqui está uma que cobre todas as necessidades em que eu poderia pensar:
E então, você pode usar:
string.substring(from: 1, to: 7)
recebe você:ello,Wo
string.substring(to: 7)
recebe você:Hello,Wo
string.substring(from: 3)
recebe você:lo,World!
string.substring(from: 1, length: 4)
recebe você:ello
string.substring(length: 4, to: 7)
recebe você:o,Wo
Atualizado
substring(from: Int?, length: Int)
para oferecer suporte a partir do zero.fonte
"Hello😇😍😘😎📸📀💾∝ℵℶ≹".substring(from: 4, to: 14)
nos dá:o😇😍😘😎📸📀💾∝ℵℶ
SWIFT 2.0
simples:
SWIFT 3.0
SWIFT 4.0
As operações de substring retornam uma instância do tipo Substring, em vez de String.
fonte
text[text.startIndex..<text.index(text.startIndex, offsetBy: 2)]
É muito mais simples do que qualquer uma das respostas aqui, depois de encontrar a sintaxe correta.
Eu quero tirar o [e]
resultado será "ABCDEFGHI", o startIndex e o endIndex também podem ser usados em
e assim por diante!
PS: Conforme indicado nas observações, há algumas alterações de sintaxe no swift 2 que vem com o xcode 7 e iOS9!
Por favor, veja esta página
fonte
advance(myString.endIndex, -1)
sintaxe do Xcode 7 beta 6 mudou paramyString.endIndex.advancedBy(-1)
Por exemplo, para encontrar o primeiro nome (até o primeiro espaço) no meu nome completo:
start
eend
são do tipoString.Index
aqui e são usadas para criar umRange<String.Index>
e usado no acessador subscrito (se um espaço for encontrado na string original).É difícil criar um
String.Index
diretamente a partir de uma posição inteira, como usado no post de abertura. Isso ocorre porque, em meu nome, cada caractere teria o mesmo tamanho em bytes. Mas caracteres usando acentos especiais em outros idiomas poderiam ter usado mais bytes (dependendo da codificação usada). Então, a que byte o número inteiro deve se referir?É possível criar um novo a
String.Index
partir de um já existente usando os métodossucc
epred
que garantirão que o número correto de bytes seja pulado para chegar ao próximo ponto de código na codificação. No entanto, nesse caso, é mais fácil procurar o índice do primeiro espaço da string para encontrar o índice final.fonte
Para mim, essa é a parte realmente interessante da sua pergunta. Cadeia é ponte para NSString, de modo mais métodos NSString fazer o trabalho diretamente em uma corda. Você pode usá-los livremente e sem pensar. Então, por exemplo, isso funciona exatamente como você espera:
Mas, como tantas vezes acontece, "fiz meu trabalho funcionar, mas simplesmente não funciona em você". Por acaso, você escolheu um dos raros casos em que existe um método Swift paralelo chamado de forma idêntica e, em um caso como esse, o método Swift ofusca o método Objective-C. Assim, quando você diz
str.substringWithRange
, Swift pensa que você quer dizer o método Swift, e não o método NSString - e então você é processado, porque o método Swift espera aRange<String.Index>
e você não sabe como criar um deles.O caminho mais fácil é impedir que o Swift se ofereça dessa maneira, lançando explicitamente:
Observe que nenhum trabalho extra significativo está envolvido aqui. "Transmitir" não significa "converter"; a String é efetivamente uma NSString. Estamos apenas dizendo ao Swift como olhar para essa variável para fins dessa linha de código.
A parte realmente estranha dessa coisa toda é que o método Swift, que causa todo esse problema, não é documentado. Não faço ideia de onde está definido; não está no cabeçalho NSString e também não está no cabeçalho Swift.
fonte
Range<String.Index>
ou tirar esse método não documentado do nosso caminho.No novo Xcode 7.0, use
fonte
.advancedBy(0)
não é necessário para startIndex.A resposta curta é que isso é realmente difícil no Swift agora. Meu palpite é que ainda há muito trabalho para a Apple fazer em métodos de conveniência para coisas como essa.
String.substringWithRange()
está esperando umRange<String.Index>
parâmetro e, até onde eu sei, não existe um método gerador para oString.Index
tipo Você pode obterString.Index
valores de volta deaString.startIndex
eaString.endIndex
e chamada.succ()
ou.pred()
sobre eles, mas isso é loucura.Que tal uma extensão na classe String que leva bons velhos
Int
tempos?Atualização: Swift beta 4 resolve os problemas abaixo!
Como está no [beta 3 e versões anteriores], até as strings nativas do Swift têm alguns problemas ao lidar com caracteres Unicode. O ícone do cachorro acima funcionou, mas o seguinte não:
Resultado:
fonte
NSString
me fez pensar que eu estava usando apenasString
métodos nativos do Swift , já que não estava usando nenhumamyString as NSString
ligação.Você pode usar essas extensões para melhorar
substringWithRange
Swift 2.3
Swift 3
Uso:
fonte
Código de exemplo para obter substring no Swift 2.0
(i) Substring do índice inicial
Entrada:-
Resultado:-
(ii) Substring de um índice específico
Entrada:-
Resultado:-
Espero que ajude você!
fonte
Solução fácil com pouco código.
Faça uma extensão que inclua subStringing básico que quase todos os outros idiomas tenham:
Basta chamar isso com
fonte
Isso funciona no meu playground :)
fonte
advance
Atualizado para o Xcode 7. Adiciona extensão String:
Usar:
Implementação:
fonte
tente isso no playground
vai te dar "ello, p"
No entanto, onde isso fica realmente interessante é que, se você tornar o último índice maior que a string no playground, ela mostrará quaisquer strings que você definiu após str: o
Range () parece ser uma função genérica para que ele precise saber o tipo com o qual está lidando.
Você também precisa fornecer a string real de seu interesse nos playgrounds, pois parece conter todas as picadas em uma sequência, uma após a outra, com o nome da variável posteriormente.
assim
dá "ello, playground str Sou a próxima string str2 "
funciona mesmo se str2 for definido com um let
:)
fonte
Rob Napier já tinha dado uma resposta impressionante usando subscrito. Mas senti uma desvantagem, pois não há verificação de condições fora do limite. Isso pode tender a falhar. Então eu modifiquei a extensão e aqui está
Saída abaixo
Então, eu sugiro sempre verificar o if let
fonte
Na Swift3
Por exemplo: uma variável "Duke James Thomas", precisamos obter "James".
fonte
Tomando uma página de Rob Napier, desenvolvi essas Common String Extensions , duas das quais são:
Uso:
fonte
Range
vez deRange<String.Index>
obrigado para digitar inferência.É assim que você obtém um intervalo de uma string:
O ponto principal é que você está passando um intervalo de valores do tipo String.Index (é isso que o avanço retorna) em vez de números inteiros.
A razão pela qual isso é necessário é que as seqüências de caracteres no Swift não têm acesso aleatório (basicamente devido ao comprimento variável dos caracteres Unicode). Você também não pode fazer
str[1]
. String.Index foi projetado para funcionar com sua estrutura interna.Você pode criar uma extensão com um índice subscrito, que faz isso por você, para que você possa passar um intervalo de números inteiros (veja, por exemplo, a resposta de Rob Napier ).
fonte
Eu tentei inventar algo pythonic.
Todos os subscritos aqui são ótimos, mas os momentos em que realmente preciso de algo simples são geralmente quando quero contar de volta, por exemplo
string.endIndex.advancedBy(-1)
Ele suporta
nil
valores, tanto para o índice inicial quanto para o final, ondenil
significaria índice em 0 para início estring.characters.count
fim.EDITAR
Uma solução mais elegante:
fonte
Primeiro crie o intervalo, depois a substring. Você pode usar a
fromIndex..<toIndex
sintaxe da seguinte maneira:fonte
Aqui está um exemplo para obter apenas o ID de vídeo .ie (6oL687G0Iso) de todo o URL rapidamente
fonte
Amostra completa você pode ver aqui
fonte
http://www.learnswiftonline.com/reference-guides/string-reference-guide-for-swift/ mostra que isso funciona bem:
fonte
Bem, eu tive o mesmo problema e resolvi com a função "bridgeToObjectiveC ()":
Observe que, no exemplo, substringWithRange em conjunto com NSMakeRange ocupa a parte da sequência iniciando no índice 6 (caractere "W") e finalizando nas posições 6 + 6 do índice à frente (caractere "!")
Felicidades.
fonte
Você pode usar qualquer um dos métodos de substring em uma extensão Swift String que escrevi https://bit.ly/JString .
fonte
Se você tiver um
NSRange
, a ponteNSString
funciona perfeitamente. Por exemplo, eu estava trabalhando um poucoUITextFieldDelegate
e rapidamente quis calcular o novo valor da string quando ele perguntou se deveria substituir o intervalo.fonte
Extensão simples para
String
:fonte
Se você não se importa com o desempenho ... essa é provavelmente a solução mais concisa no Swift 4
Ele permite que você faça algo assim:
fonte