Estou atualizando alguns dos meus códigos e respostas antigos com o Swift 3, mas quando cheguei ao Swift Strings e à indexação com substrings, as coisas ficaram confusas.
Especificamente, eu estava tentando o seguinte:
let str = "Hello, playground"
let prefixRange = str.startIndex..<str.startIndex.advancedBy(5)
let prefix = str.substringWithRange(prefixRange)
onde a segunda linha estava me dando o seguinte erro
O valor do tipo 'String' não possui membro 'substringWithRange'
Vejo que String
agora tem os seguintes métodos:
str.substring(to: String.Index)
str.substring(from: String.Index)
str.substring(with: Range<String.Index>)
Isso realmente me confundiu no começo, então comecei a brincar com o índice e o alcance . Esta é uma pergunta de acompanhamento e resposta para substring. Estou adicionando uma resposta abaixo para mostrar como eles são usados.
Respostas:
Todos os exemplos a seguir usam
Swift 4
Strings sofreu uma grande reforma no Swift 4. Quando você obtém alguma substring de um String agora, recebe um
Substring
tipo de volta em vez de aString
. Por que é isso? Strings são tipos de valor no Swift. Isso significa que, se você usar uma String para criar uma nova, ela deverá ser copiada. Isso é bom para a estabilidade (ninguém mais vai mudar isso sem o seu conhecimento), mas é ruim para a eficiência.Uma Substring, por outro lado, é uma referência à String original da qual ela veio. Aqui está uma imagem da documentação que ilustra isso.
Nenhuma cópia é necessária, por isso é muito mais eficiente de usar. No entanto, imagine que você tenha um Substring de dez caracteres de um milhão de caracteres. Como a Substring está referenciando a String, o sistema precisaria manter a String inteira enquanto a Substring estiver disponível. Assim, sempre que você terminar de manipular seu Substring, converta-o em uma String.
Isso copiará apenas a substring e a memória contendo String antiga pode ser recuperada . Substrings (como um tipo) devem durar pouco.
Outra grande melhoria no Swift 4 é que Strings são coleções (novamente). Isso significa que tudo o que você pode fazer em uma coleção, você pode fazer em uma string (use subscritos, itere sobre os caracteres, filtro, etc.).
Os exemplos a seguir mostram como obter uma substring no Swift.
Obtendo substrings
Você pode obter uma substring de uma string usando subscritos ou uma série de outros métodos (por exemplo,
prefix
,suffix
,split
). Você ainda precisa usarString.Index
e não umInt
índice para o intervalo. (Veja minha outra resposta se precisar de ajuda com isso.)Início de uma string
Você pode usar um índice (observe o intervalo unilateral do Swift 4):
ou
prefix
:ou ainda mais fácil:
Fim de uma string
Usando subscritos:
ou
suffix
:ou ainda mais fácil:
Observe que, ao usar o
suffix(from: index)
, tive que contar novamente desde o final usando-10
. Isso não é necessário quando se está usandosuffix(x)
, o que leva apenas os últimosx
caracteres de uma String.Intervalo em uma sequência
Novamente, simplesmente usamos subscritos aqui.
Convertendo
Substring
paraString
Não se esqueça, quando estiver pronto para salvar sua substring, converta-a em um
String
para que a memória da string antiga possa ser limpa.Usando uma
Int
extensão de índice?Hesito em usar uma
Int
extensão de índice baseada depois de ler o artigo Strings in Swift 3 da Airspeed Velocity e Ole Begemann. Embora no Swift 4, Strings sejam coleções, a equipe do Swift propositalmente não usouInt
índices. Ainda estáString.Index
. Isso tem a ver com caracteres Swift sendo compostos por números variáveis de pontos de código Unicode. O índice real deve ser calculado exclusivamente para cada string.Devo dizer que espero que a equipe Swift encontre uma maneira de abstrair
String.Index
no futuro. Mas até eles eu estou escolhendo usar sua API. Isso me ajuda a lembrar que as manipulações de String não são apenas simplesInt
pesquisas de índice.fonte
garbage collected
;-) Espero que as pessoas aqui saibam que não há coleta de lixo no Swift.Estou realmente frustrado com o modelo de acesso de Swift à String: tudo tem que ser um
Index
. Tudo o que eu quero é acessar o i-ésimo caractere da string usandoInt
, não o índice desajeitado e o avanço (o que acontece a cada versão principal). Então eu fiz uma extensão paraString
:fonte
let str = "🇨🇭🇩🇪🇺🇸Hello"
print(str.substring(to: 2))
str[5]
, quero acessar o caractere no índice 5, seja qual for o caractere ou quantos bytes ele leva. Swift não é tudo sobre a produtividade do desenvolvedor?countElement(str)
para encontrar o comprimento. No Swift 3, a Apple criou cordas que nãoSequence
estavam em conformidade e obrigou todo mundo a usarstr.characters
. Esses caras não têm medo de fazer alterações. Sua teimosia em inteiro subscripting em realmente difícil de entenderExtensão Swift 5:
Uso:
Ou unicode:
fonte
count
estava disponível apenas emself.characters
CountableClosedRange<Int>
se você gostaria de escrever, por exemplos[0...2]
.Swift 4 e 5:
Como usá-lo:
fonte
Swift 4
Em rápido 4
String
está em conformidade comCollection
. Em vez desubstring
, devemos agora usar umsubscript.
Então, se você quer cortar somente a palavra"play"
de"Hello, playground"
, você poderia fazê-lo como este:É interessante saber que isso lhe dará um em
Substring
vez de umString
. Isso é rápido e eficiente comoSubstring
compartilha seu armazenamento com a String original. No entanto, o compartilhamento de memória dessa maneira também pode levar facilmente a vazamentos de memória.É por isso que você deve copiar o resultado em uma nova String, assim que desejar limpar a String original. Você pode fazer isso usando o construtor normal:
Você pode encontrar mais informações sobre a nova
Substring
classe na [documentação da Apple]. 1 1Portanto, se você, por exemplo, obtiver a
Range
como resultado de umaNSRegularExpression
, poderá usar a seguinte extensão:fonte
text[Range( nsRange , in: text)!]
Aqui está uma função que retorna a substring de uma determinada substring quando os índices inicial e final são fornecidos. Para referência completa, você pode visitar os links abaixo.
Aqui está um link para o post do blog que eu criei para lidar com a manipulação de seqüências rapidamente. Manipulação de strings no swift (também abrange o swift 4)
Ou você pode ver essa essência no github
fonte
Eu tive a mesma reação inicial. Também fiquei frustrado com a forma como a sintaxe e os objetos mudam tão drasticamente em todos os principais lançamentos.
No entanto, percebi por experiência própria como sempre sofro as conseqüências de tentar combater a "mudança", como lidar com personagens de vários bytes, o que é inevitável se você estiver olhando para uma audiência global.
Por isso, decidi reconhecer e respeitar os esforços exercidos pelos engenheiros da Apple e fazer minha parte entendendo a mentalidade deles quando surgiram essa abordagem "horrível".
Em vez de criar extensões, que são apenas uma solução alternativa para facilitar sua vida (não estou dizendo que elas estejam erradas ou caras), por que não descobrir como as Strings agora são projetadas para funcionar.
Por exemplo, eu tinha esse código que estava trabalhando no Swift 2.2:
e depois de desistir de tentar fazer com que a mesma abordagem funcionasse, por exemplo, usando Substrings, finalmente entendi o conceito de tratar Strings como uma coleção bidirecional para a qual acabei com esta versão do mesmo código:
Espero que isso contribua ...
fonte
Mesma frustração, isso não deve ser tão difícil ...
Eu compilei este exemplo de obter posições para substring (s) de texto maior:
retorna ("Por que", 0, 3) ("substrings", 26, 36) ("Swift3", 40, 46)
fonte
Eu sou novo no Swift 3, mas procurando a
String
sintaxe (index) para analogia, acho que o índice é como um "ponteiro" restrito à string e o Int pode ajudar como um objeto independente. Usando a sintaxe base + offset, podemos obter o i-ésimo caractere da string com o código abaixo:Para um intervalo de caracteres (índices) de string usando a sintaxe String (range), podemos obter do i-ésésimo-quinto caracteres com o código abaixo:
Para uma substring (range) de uma string usando String.substring (range), podemos obter a substring usando o código abaixo:
Notas:
O i-ésimo e um-ésimo começam com 0.
Para f-ésimo, uso offsetBY: f + 1, porque o intervalo de assinaturas usa .. <(operador semiaberto), não inclui a f-ésima posição.
Obviamente, deve incluir erros de validação, como índice inválido.
fonte
Swift 4+
Retorna uma subsequência dos primeiros n caracteres ou a sequência inteira, se a sequência for menor. (inspirado em: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/take.html )
Exemplo:
fonte
Eu sou um pensamento bastante mecânico. Aqui estão os princípios básicos ...
Swift 4 Swift 5
O resultado é uma substring, o que significa que faz parte da string original. Para obter uma sequência separada completa, use, por exemplo,
Isto é o que eu uso:
fonte
Swift 4
fonte
Eu criei uma extensão simples para isso (Swift 3)
fonte
Aqui está uma implementação mais genérica:
Essa técnica ainda usa
index
para manter os padrões de Swift e implica um personagem completo.Para submarcar do terceiro caractere:
Eu usei camel
subString
para indicar que retorna umString
e não umSubstring
.fonte
Com base no exposto, eu precisava dividir uma sequência em um caractere não imprimível, soltando o caractere não imprimível. Eu desenvolvi dois métodos:
que montei usando algumas das respostas acima.
Como uma String é uma coleção, fiz o seguinte:
O que para mim foi mais intuitivo. Qual é o melhor? Não tenho como dizer. Ambos trabalham com o Swift 5.
fonte
Swift 4
"Substring" ( https://developer.apple.com/documentation/swift/substring ):
Exemplo de extensão String:
exemplo de uso da extensão String:
fonte
Swift 5
let desiredIndex: Int = 7 let substring = str[String.Index(encodedOffset: desiredIndex)...]
Essa variável de substring fornecerá o resultado.
Simplesmente aqui Int é convertido em Index e, em seguida, você pode dividir as strings. A menos que você obtenha erros.
fonte