¿Para qué necesitas la gama? Se usan cadenas rápidas Range<String.Index>, pero a veces es necesario trabajar con NSStringy NSRange, por lo que sería útil algo más de contexto. - Pero eche un vistazo a stackoverflow.com/questions/24092884/… .
Martin R
Respuestas:
256
Actualizado para Swift 4
Los rangos de Swift son más complejos que NSRange, y no se volvieron más fáciles en Swift 3. Si quieres tratar de comprender el razonamiento detrás de esta complejidad, lee esto y esto . Solo te mostraré cómo crearlos y cuándo puedes usarlos.
Rangos cerrados: a...b
Este operador de rango crea un rango Swift que incluye tanto el elemento acomo el elemento b, incluso si bes el valor máximo posible para un tipo (como Int.max). Hay dos tipos diferentes de rangos cerrados: ClosedRangey CountableClosedRange.
1. ClosedRange
Los elementos de todos los rangos en Swift son comparables (es decir, se ajustan al protocolo Comparable). Eso le permite acceder a los elementos en el rango de una colección. Aquí hay un ejemplo:
let myRange:ClosedRange=1...3let myArray =["a","b","c","d","e"]
myArray[myRange]//["b","c","d"]
Sin embargo, a ClosedRangeno es contable (es decir, no se ajusta al protocolo de secuencia). Eso significa que no puede iterar sobre los elementos con un forbucle. Para eso necesitas el CountableClosedRange.
2. CountableClosedRange
Esto es similar al anterior, excepto que ahora el rango también se puede iterar.
let myRange:CountableClosedRange=1...3let myArray =["a","b","c","d","e"]
myArray[myRange]// ["b", "c", "d"]
for index in myRange {
print(myArray[index])}
Rangos semiabiertos: a..<b
Este operador de rango incluye elemento apero no elemento b. Como arriba, hay dos tipos diferentes de rangos semiabiertos: Rangey CountableRange.
1. Range
Al igual que con ClosedRange, puede acceder a los elementos de una colección con un Range. Ejemplo:
let myRange:Range=1..<3let myArray =["a","b","c","d","e"]
myArray[myRange]//["b","c"]
Una vez más, sin embargo, no se puede iterar sobre un Rangeporque solo es comparable, no stridable.
2. CountableRange
A CountableRangepermite la iteración.
let myRange:CountableRange=1..<3let myArray =["a","b","c","d","e"]
myArray[myRange]// ["b", "c"]
for index in myRange {
print(myArray[index])}
NSRange
Puede (debe) usarlo NSRangea veces en Swift (al hacer cadenas con atributos , por ejemplo), por lo que es útil saber cómo hacer una.
let myNSRange =NSRange(location:3, length:2)
Tenga en cuenta que esta es la ubicación y la longitud , no el índice de inicio y el índice de finalización. El ejemplo aquí tiene un significado similar al de la gama Swift 3..<5. Sin embargo, dado que los tipos son diferentes, no son intercambiables.
Rangos con cadenas
Los operadores de rango ...y ..<son una forma abreviada de crear rangos. Por ejemplo:
let myRange =1..<3
La forma más larga de crear el mismo rango sería
let myRange =CountableRange<Int>(uncheckedBounds:(lower:1, upper:3))//1..<3
Puede ver que el tipo de índice aquí es Int. Sin embargo, eso no funciona Stringporque las cadenas están hechas de caracteres y no todos los caracteres tienen el mismo tamaño. (Lea esto para obtener más información). Un emoji como 😀, por ejemplo, ocupa más espacio que la letra "b".
Problema con NSRange
Intenta experimentar con NSRangey NSStringcon emoji y verás a qué me refiero. Dolor de cabeza.
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"!?
La carita sonriente necesita dos unidades de código UTF-16 para almacenar, por lo que da el resultado inesperado de no incluir la "d".
Solución rápida
Debido a esto, con Swift Strings usas Range<String.Index>, no Range<Int>. El índice de cadenas se calcula en función de una cadena en particular para que sepa si hay emoji o grupos de grafemas extendidos.
En Swift 4 las cosas se simplificaron un poco. Siempre que se pueda inferir el punto inicial o final de un rango, puede dejarlo.
En t
Puede utilizar rangos de enteros de un solo lado para iterar sobre colecciones. A continuación se muestran algunos ejemplos de la documentación .
// 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...
Cuerda
Esto también funciona con rangos de cadenas. Si está haciendo un rango con str.startIndexo str.endIndexen un extremo, puede dejarlo. El compilador lo inferirá.
Dado
var str ="Hello, playground"let index = str.index(str.startIndex, offsetBy:5)let myRange =..<index //Hello
Puede ir del índice a str.endIndex usando ...
var str ="Hello, playground"let index = str.index(str.endIndex, offsetBy:-10)let myRange = index...// playground
Mi comentario se refiere a la subsección "Problema con NSRange". NSStringalmacena internamente sus caracteres en codificación UTF-16. Un escalar Unicode completo es de 21 bits. El carácter de cara sonriente ( U+1F600) no se puede almacenar en una sola unidad de código de 16 bits, por lo que se distribuye en 2. NSRangerecuentos basados en unidades de código de 16 bits. En este ejemplo, 3 unidades de código representan solo 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)
Veo que tienen el tipo de datos "Rango". Entonces, ¿cómo puedo usarlo?
vichhai
@vichhai ¿Puedes explicar más dónde quieres usar?
Dharmbir Singh
Como en el objetivo c: NSRange range;
vichhai
1
Me sorprende que, incluso en Swift 4, todavía no haya una forma nativa simple de expresar un rango de cadenas usando Int. Los únicos métodos de cadena que le permiten proporcionar un Int como una forma de obtener una subcadena por rango son prefixysuffix .
Es útil tener a mano algunas utilidades de conversión, para que podamos hablar como NSRange cuando hablamos con un String. Aquí hay una utilidad que toma una ubicación y una longitud, como NSRange, y devuelve Range<String.Index>:
Por ejemplo, "hello".range(0,1)"es el Range<String.Index>abrazo el primer personaje de "hello". Como beneficio adicional, he permitido ubicaciones negativas: "hello".range(-1,1)"es el Range<String.Index>abrazo el último carácter de"hello" .
También es útil convertir Range<String.Index>a en NSRange, para esos momentos en los que tienes que hablar con Cocoa (por ejemplo, al tratar con rangos de atributos NSAttributedString). Swift 4 proporciona una forma nativa de hacerlo:
let nsrange =NSRange(range,in:s)//where s is the string
Por lo tanto, podemos escribir otra utilidad en la que vayamos directamente desde una ubicación y longitud de String a un NSRange:
let nsRange =NSRange(location: someInt, length: someInt)
como en
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>
, pero a veces es necesario trabajar conNSString
yNSRange
, por lo que sería útil algo más de contexto. - Pero eche un vistazo a stackoverflow.com/questions/24092884/… .Respuestas:
Actualizado para Swift 4
Los rangos de Swift son más complejos que
NSRange
, y no se volvieron más fáciles en Swift 3. Si quieres tratar de comprender el razonamiento detrás de esta complejidad, lee esto y esto . Solo te mostraré cómo crearlos y cuándo puedes usarlos.Rangos cerrados:
a...b
Este operador de rango crea un rango Swift que incluye tanto el elemento
a
como el elementob
, incluso sib
es el valor máximo posible para un tipo (comoInt.max
). Hay dos tipos diferentes de rangos cerrados:ClosedRange
yCountableClosedRange
.1.
ClosedRange
Los elementos de todos los rangos en Swift son comparables (es decir, se ajustan al protocolo Comparable). Eso le permite acceder a los elementos en el rango de una colección. Aquí hay un ejemplo:
Sin embargo, a
ClosedRange
no es contable (es decir, no se ajusta al protocolo de secuencia). Eso significa que no puede iterar sobre los elementos con unfor
bucle. Para eso necesitas elCountableClosedRange
.2.
CountableClosedRange
Esto es similar al anterior, excepto que ahora el rango también se puede iterar.
Rangos semiabiertos:
a..<b
Este operador de rango incluye elemento
a
pero no elementob
. Como arriba, hay dos tipos diferentes de rangos semiabiertos:Range
yCountableRange
.1.
Range
Al igual que con
ClosedRange
, puede acceder a los elementos de una colección con unRange
. Ejemplo:Una vez más, sin embargo, no se puede iterar sobre un
Range
porque solo es comparable, no stridable.2.
CountableRange
A
CountableRange
permite la iteración.NSRange
Puede (debe) usarlo
NSRange
a veces en Swift (al hacer cadenas con atributos , por ejemplo), por lo que es útil saber cómo hacer una.Tenga en cuenta que esta es la ubicación y la longitud , no el índice de inicio y el índice de finalización. El ejemplo aquí tiene un significado similar al de la gama Swift
3..<5
. Sin embargo, dado que los tipos son diferentes, no son intercambiables.Rangos con cadenas
Los operadores de rango
...
y..<
son una forma abreviada de crear rangos. Por ejemplo:La forma más larga de crear el mismo rango sería
Puede ver que el tipo de índice aquí es
Int
. Sin embargo, eso no funcionaString
porque las cadenas están hechas de caracteres y no todos los caracteres tienen el mismo tamaño. (Lea esto para obtener más información). Un emoji como 😀, por ejemplo, ocupa más espacio que la letra "b".Problema con NSRange
Intenta experimentar con
NSRange
yNSString
con emoji y verás a qué me refiero. Dolor de cabeza.La carita sonriente necesita dos unidades de código UTF-16 para almacenar, por lo que da el resultado inesperado de no incluir la "d".
Solución rápida
Debido a esto, con Swift Strings usas
Range<String.Index>
, noRange<Int>
. El índice de cadenas se calcula en función de una cadena en particular para que sepa si hay emoji o grupos de grafemas extendidos.Ejemplo
Rangos unilaterales:
a...
y...b
y..<b
En Swift 4 las cosas se simplificaron un poco. Siempre que se pueda inferir el punto inicial o final de un rango, puede dejarlo.
En t
Puede utilizar rangos de enteros de un solo lado para iterar sobre colecciones. A continuación se muestran algunos ejemplos de la documentación .
Cuerda
Esto también funciona con rangos de cadenas. Si está haciendo un rango con
str.startIndex
ostr.endIndex
en un extremo, puede dejarlo. El compilador lo inferirá.Dado
Puede ir del índice a str.endIndex usando
...
Ver también:
Notas
Estudio adicional
fuente
NSString
almacena internamente sus caracteres en codificación UTF-16. Un escalar Unicode completo es de 21 bits. El carácter de cara sonriente (U+1F600
) no se puede almacenar en una sola unidad de código de 16 bits, por lo que se distribuye en 2.NSRange
recuentos basados en unidades de código de 16 bits. En este ejemplo, 3 unidades de código representan solo 2 caracteresXcode 8 beta 2 • Swift 3
Xcode 7 • Swift 2.0
o simplemente
fuente
devoluciones...
fuente
Úselo así
Salida: Hola
fuente
Me sorprende que, incluso en Swift 4, todavía no haya una forma nativa simple de expresar un rango de cadenas usando Int. Los únicos métodos de cadena que le permiten proporcionar un Int como una forma de obtener una subcadena por rango son
prefix
ysuffix
.Es útil tener a mano algunas utilidades de conversión, para que podamos hablar como NSRange cuando hablamos con un String. Aquí hay una utilidad que toma una ubicación y una longitud, como NSRange, y devuelve
Range<String.Index>
:Por ejemplo,
"hello".range(0,1)"
es elRange<String.Index>
abrazo el primer personaje de"hello"
. Como beneficio adicional, he permitido ubicaciones negativas:"hello".range(-1,1)"
es elRange<String.Index>
abrazo el último carácter de"hello"
.También es útil convertir
Range<String.Index>
a en NSRange, para esos momentos en los que tienes que hablar con Cocoa (por ejemplo, al tratar con rangos de atributos NSAttributedString). Swift 4 proporciona una forma nativa de hacerlo:Por lo tanto, podemos escribir otra utilidad en la que vayamos directamente desde una ubicación y longitud de String a un NSRange:
fuente
Si alguien quiere crear un objeto NSRange puede crearlo como:
esto creará un rango con posición 0 y longitud 5
fuente
Creé la siguiente extensión:
ejemplo de uso:
fuente
Puedes usar así
como en
fuente
Quiero hacer esto:
Pero, desafortunadamente, no puedo escribir un subíndice propio porque el odiado ocupa el espacio del nombre.
Sin embargo, podemos hacer esto:
Simplemente agregue esto a su proyecto:
fuente
fuente