Para que você precisa do intervalo? Strings swift usam Range<String.Index>, mas às vezes é necessário trabalhar com NSStringe NSRange, então um pouco mais de contexto seria útil. - Mas dê uma olhada em stackoverflow.com/questions/24092884/… .
Martin R
Respostas:
258
Atualizado para Swift 4
Intervalos de Swift são mais complexos do que NSRange, e eles não ficaram mais fáceis no Swift 3. Se você quiser tentar entender o raciocínio por trás de alguma desta complexidade, leia isto e isto . Vou apenas mostrar como criá-los e quando você pode usá-los.
Faixas fechadas: a...b
Este operador de intervalo cria um intervalo Swift que inclui elemento ae elemento b, mesmo se bfor o valor máximo possível para um tipo (como Int.max). Existem dois tipos diferentes de intervalos fechados: ClosedRangee CountableClosedRange.
1 ClosedRange
Os elementos de todas as faixas em Swift são comparáveis (ou seja, eles estão em conformidade com o protocolo Comparable). Isso permite que você acesse os elementos no intervalo de uma coleção. Aqui está um exemplo:
let myRange:ClosedRange=1...3let myArray =["a","b","c","d","e"]
myArray[myRange]//["b","c","d"]
No entanto, a ClosedRangenão é contável (ou seja, não está em conformidade com o protocolo de Sequência). Isso significa que você não pode iterar sobre os elementos com um forloop. Para isso, você precisa do CountableClosedRange.
2 CountableClosedRange
É semelhante ao anterior, exceto que agora o intervalo também pode ser iterado.
let myRange:CountableClosedRange=1...3let myArray =["a","b","c","d","e"]
myArray[myRange]// ["b", "c", "d"]
for index in myRange {
print(myArray[index])}
Faixas semi-abertas: a..<b
Este operador de intervalo inclui elemento, amas não elemento b. Como acima, existem dois tipos diferentes de intervalos semiabertos: Rangee CountableRange.
1 Range
Assim como com ClosedRange, você pode acessar os elementos de uma coleção com a Range. Exemplo:
let myRange:Range=1..<3let myArray =["a","b","c","d","e"]
myArray[myRange]//["b","c"]
Novamente, porém, você não pode iterar sobre a Rangeporque ele é apenas comparável, não passível de stridging.
2 CountableRange
A CountableRangepermite a iteração.
let myRange:CountableRange=1..<3let myArray =["a","b","c","d","e"]
myArray[myRange]// ["b", "c"]
for index in myRange {
print(myArray[index])}
NSRange
Você ainda pode (deve) usar NSRangeàs vezes em Swift (ao fazer strings atribuídas , por exemplo), por isso é útil saber como fazer uma.
let myNSRange =NSRange(location:3, length:2)
Observe que este é o local e o comprimento , não o índice inicial e o índice final. O exemplo aqui é semelhante ao significado da faixa Swift 3..<5. No entanto, como os tipos são diferentes, eles não são intercambiáveis.
Faixas com cordas
Os operadores de intervalo ...e ..<são uma forma abreviada de criar intervalos. Por exemplo:
let myRange =1..<3
O longo caminho para criar o mesmo intervalo seria
let myRange =CountableRange<Int>(uncheckedBounds:(lower:1, upper:3))//1..<3
Você pode ver que o tipo de índice aqui é Int. Isso não funciona String, porque Strings são feitos de caracteres e nem todos os caracteres têm o mesmo tamanho. (Leia isto para obter mais informações.) Um emoji como 😀, por exemplo, ocupa mais espaço do que a letra "b".
Problema com NSRange
Experimente experimentar com NSRangee NSStringcom emoji e você verá o que quero dizer. Dor de cabeça.
let myNSRange =NSRange(location:1, length:3)let myNSString:NSString="abcde"
myNSString.substring(with: myNSRange)// "bcd"
let myNSString2:NSString="a😀cde"
myNSString2.substring(with: myNSRange)//"😀c"Whereis the "d"!?
O rosto sorridente precisa de duas unidades de código UTF-16 para armazenar, então dá o resultado inesperado de não incluir o "d".
Solução rápida
Por causa disso, com Swift Strings você usa Range<String.Index>, não Range<Int>. O Índice de Sequência é calculado com base em uma sequência específica para que ele saiba se há algum emoji ou agrupamento de grafemas estendidos.
No Swift 4 as coisas foram um pouco simplificadas. Sempre que o ponto inicial ou final de um intervalo pode ser inferido, você pode deixá-lo desativado.
Int
Você pode usar intervalos inteiros de um lado para iterar nas coleções. Aqui estão alguns exemplos da documentação .
// iterate from index 2 to the end of the array
for name in names[2...]{
print(name)}// iterate from the beginning of the array to index 2
for name in names[...2]{
print(name)}// iterate from the beginning of the array up to but not including index 2
for name in names[..<2]{
print(name)}// the range from negative infinity to 5. You can't iterate forward
// over this because the starting point in unknown.
let range =...5
range.contains(7)// false
range.contains(4)// true
range.contains(-1)// true
// You can iterate over this but it will be an infinate loop
// so you have to break out at some point.
let range =5...
Corda
Isso também funciona com intervalos de String. Se estiver fazendo um intervalo com str.startIndexou str.endIndexem uma extremidade, você pode deixá-lo desativado. O compilador irá inferir isso.
Dado
var str ="Hello, playground"let index = str.index(str.startIndex, offsetBy:5)let myRange =..<index //Hello
Você pode ir do índice para str.endIndex usando ...
var str ="Hello, playground"let index = str.index(str.endIndex, offsetBy:-10)let myRange = index...// playground
Meu comentário se refere à subseção "Problema com NSRange". NSStringarmazena internamente seus caracteres na codificação UTF-16. Um escalar unicode completo tem 21 bits. O caractere de rosto sorridente ( U+1F600) não pode ser armazenado em uma única unidade de código de 16 bits, portanto, é distribuído por 2. NSRangecontagens baseadas em unidades de código de 16 bits. Neste exemplo, 3 unidades de código representam apenas 2 caracteres
var start = str.startIndex // Start at the string's start index
var end = advance(str.startIndex,5)// Take start index and advance 5 characters forward
var range:Range<String.Index>=Range<String.Index>(start: start,end: end)let firstFiveDigit = str.substringWithRange(range)
print(firstFiveDigit)
Vejo que eles têm o tipo de dados "Range". Então, como posso usar isso?
vichhai
@vichhai Você pode explicar mais onde deseja usar?
Dharmbir Singh
Como no objetivo c: intervalo NSRange;
vichhai
1
Acho surpreendente que, mesmo no Swift 4, ainda não haja uma maneira nativa simples de expressar um intervalo de String usando Int. Os únicos métodos String que permitem fornecer um Int como forma de obter uma substring por intervalo são prefixe suffix.
É útil ter em mãos alguns utilitários de conversão, para que possamos falar como NSRange ao falar com uma String. Este é um utilitário que pega um local e comprimento, assim como NSRange, e retorna um Range<String.Index>:
Por exemplo, "hello".range(0,1)"é o Range<String.Index>abraçando o primeiro personagem de "hello". Como um bônus, permiti locais negativos: "hello".range(-1,1)"é o Range<String.Index>abraço do último personagem de"hello" .
É útil também converter a Range<String.Index>em NSRange, para aqueles momentos em que você precisa falar com Cocoa (por exemplo, ao lidar com intervalos de atributos NSAttributedString). O Swift 4 oferece uma maneira nativa de fazer isso:
let nsrange =NSRange(range,in:s)//where s is the string
Podemos, portanto, escrever outro utilitário onde vamos diretamente de um local e comprimento de String para um NSRange:
let nsRange =NSRange(location: someInt, length: someInt)
como em
let myNSString = bigTOTPCode asNSString//12345678
let firstDigit = myNSString.substringWithRange(NSRange(location:0, length:1))//1
let secondDigit = myNSString.substringWithRange(NSRange(location:1, length:1))//2
let thirdDigit = myNSString.substringWithRange(NSRange(location:2, length:4))//3456
Range<String.Index>
, mas às vezes é necessário trabalhar comNSString
eNSRange
, então um pouco mais de contexto seria útil. - Mas dê uma olhada em stackoverflow.com/questions/24092884/… .Respostas:
Atualizado para Swift 4
Intervalos de Swift são mais complexos do que
NSRange
, e eles não ficaram mais fáceis no Swift 3. Se você quiser tentar entender o raciocínio por trás de alguma desta complexidade, leia isto e isto . Vou apenas mostrar como criá-los e quando você pode usá-los.Faixas fechadas:
a...b
Este operador de intervalo cria um intervalo Swift que inclui elemento
a
e elementob
, mesmo seb
for o valor máximo possível para um tipo (comoInt.max
). Existem dois tipos diferentes de intervalos fechados:ClosedRange
eCountableClosedRange
.1
ClosedRange
Os elementos de todas as faixas em Swift são comparáveis (ou seja, eles estão em conformidade com o protocolo Comparable). Isso permite que você acesse os elementos no intervalo de uma coleção. Aqui está um exemplo:
No entanto, a
ClosedRange
não é contável (ou seja, não está em conformidade com o protocolo de Sequência). Isso significa que você não pode iterar sobre os elementos com umfor
loop. Para isso, você precisa doCountableClosedRange
.2
CountableClosedRange
É semelhante ao anterior, exceto que agora o intervalo também pode ser iterado.
Faixas semi-abertas:
a..<b
Este operador de intervalo inclui elemento,
a
mas não elementob
. Como acima, existem dois tipos diferentes de intervalos semiabertos:Range
eCountableRange
.1
Range
Assim como com
ClosedRange
, você pode acessar os elementos de uma coleção com aRange
. Exemplo:Novamente, porém, você não pode iterar sobre a
Range
porque ele é apenas comparável, não passível de stridging.2
CountableRange
A
CountableRange
permite a iteração.NSRange
Você ainda pode (deve) usar
NSRange
às vezes em Swift (ao fazer strings atribuídas , por exemplo), por isso é útil saber como fazer uma.Observe que este é o local e o comprimento , não o índice inicial e o índice final. O exemplo aqui é semelhante ao significado da faixa Swift
3..<5
. No entanto, como os tipos são diferentes, eles não são intercambiáveis.Faixas com cordas
Os operadores de intervalo
...
e..<
são uma forma abreviada de criar intervalos. Por exemplo:O longo caminho para criar o mesmo intervalo seria
Você pode ver que o tipo de índice aqui é
Int
. Isso não funcionaString
, porque Strings são feitos de caracteres e nem todos os caracteres têm o mesmo tamanho. (Leia isto para obter mais informações.) Um emoji como 😀, por exemplo, ocupa mais espaço do que a letra "b".Problema com NSRange
Experimente experimentar com
NSRange
eNSString
com emoji e você verá o que quero dizer. Dor de cabeça.O rosto sorridente precisa de duas unidades de código UTF-16 para armazenar, então dá o resultado inesperado de não incluir o "d".
Solução rápida
Por causa disso, com Swift Strings você usa
Range<String.Index>
, nãoRange<Int>
. O Índice de Sequência é calculado com base em uma sequência específica para que ele saiba se há algum emoji ou agrupamento de grafemas estendidos.Exemplo
Intervalos de um lado:
a...
e...b
e..<b
No Swift 4 as coisas foram um pouco simplificadas. Sempre que o ponto inicial ou final de um intervalo pode ser inferido, você pode deixá-lo desativado.
Int
Você pode usar intervalos inteiros de um lado para iterar nas coleções. Aqui estão alguns exemplos da documentação .
Corda
Isso também funciona com intervalos de String. Se estiver fazendo um intervalo com
str.startIndex
oustr.endIndex
em uma extremidade, você pode deixá-lo desativado. O compilador irá inferir isso.Dado
Você pode ir do índice para str.endIndex usando
...
Veja também:
Notas
Um estudo mais aprofundado
fonte
NSString
armazena internamente seus caracteres na codificação UTF-16. Um escalar unicode completo tem 21 bits. O caractere de rosto sorridente (U+1F600
) não pode ser armazenado em uma única unidade de código de 16 bits, portanto, é distribuído por 2.NSRange
contagens baseadas em unidades de código de 16 bits. Neste exemplo, 3 unidades de código representam apenas 2 caracteresXcode 8 beta 2 • Swift 3
Xcode 7 • Swift 2.0
ou simplesmente
fonte
retorna ...
fonte
Usar assim
Resultado: Olá
fonte
Acho surpreendente que, mesmo no Swift 4, ainda não haja uma maneira nativa simples de expressar um intervalo de String usando Int. Os únicos métodos String que permitem fornecer um Int como forma de obter uma substring por intervalo são
prefix
esuffix
.É útil ter em mãos alguns utilitários de conversão, para que possamos falar como NSRange ao falar com uma String. Este é um utilitário que pega um local e comprimento, assim como NSRange, e retorna um
Range<String.Index>
:Por exemplo,
"hello".range(0,1)"
é oRange<String.Index>
abraçando o primeiro personagem de"hello"
. Como um bônus, permiti locais negativos:"hello".range(-1,1)"
é oRange<String.Index>
abraço do último personagem de"hello"
.É útil também converter a
Range<String.Index>
em NSRange, para aqueles momentos em que você precisa falar com Cocoa (por exemplo, ao lidar com intervalos de atributos NSAttributedString). O Swift 4 oferece uma maneira nativa de fazer isso:Podemos, portanto, escrever outro utilitário onde vamos diretamente de um local e comprimento de String para um NSRange:
fonte
Se alguém quiser criar um objeto NSRange pode criar como:
isso criará um intervalo com posição 0 e comprimento 5
fonte
fonte
Criei a seguinte extensão:
exemplo de uso:
fonte
Você pode usar assim
como em
fonte
Eu quero fazer isso:
Mas, infelizmente, não posso escrever um subscrito próprio porque o odiado ocupa o espaço do nome.
Podemos fazer isso no entanto:
Basta adicionar ao seu projeto:
fonte