J'ai donc trouvé des problèmes liés au cas de la conversion de NSRange
en Range<String.Index>
, mais je suis en fait confronté au problème inverse.
Tout simplement, j'ai une String
et un Range<String.Index>
et j'ai besoin de convertir ce dernier en un NSRange
pour une utilisation avec une fonction plus ancienne.
Jusqu'à présent, ma seule solution de contournement a été de récupérer une sous-chaîne comme ceci:
func foo(theString: String, inRange: Range<String.Index>?) -> Bool {
let theSubString = (nil == inRange) ? theString : theString.substringWithRange(inRange!)
return olderFunction(theSubString, NSMakeRange(0, countElements(theSubString)))
}
Cela fonctionne bien sûr, mais ce n'est pas très joli, je préférerais éviter de saisir une sous-chaîne et simplement utiliser la plage elle-même, est-ce possible?
Si vous regardez dans la définition de String.Index
, vous trouverez:
struct Index : BidirectionalIndexType, Comparable, Reflectable {
/// Returns the next consecutive value after `self`.
///
/// Requires: the next value is representable.
func successor() -> String.Index
/// Returns the previous consecutive value before `self`.
///
/// Requires: the previous value is representable.
func predecessor() -> String.Index
/// Returns a mirror that reflects `self`.
func getMirror() -> MirrorType
}
Donc, en réalité, il n’ya aucun moyen de le convertir en Int
et cela pour une bonne raison. Selon l'encodage de la chaîne, les caractères individuels occupent un nombre d'octets différent. Le seul moyen serait de compter le nombre d'opérations successor
nécessaires pour atteindre le String.Index
souhaité.
Edit La définition de String
a changé au fil des différentes versions de Swift, mais c’est fondamentalement la même réponse. Pour voir la définition très courante, cliquez simplement sur CMD sur une définition String
dans XCode pour accéder à la racine (fonctionne également pour les autres types).
La distanceTo
est une extension qui va à une variété de protocoles. Recherchez-le simplement dans la source String
après le clic sur CMD.
let index: Int = string.startIndex.distanceTo(range.startIndex)
Dans Swift 4, distanceTo()
est obsolète. Vous devrez peut-être convertir String
en NSString
pour tirer parti de sa méthode -[NSString rangeOfString:]
, qui renvoie une NSRange
.
Solution complète Swift 4:
OffsetIndexableCollection (Chaîne utilisant Int Index)
https://github.com/frogcjn/OffsetIndexableCollection-String-Int-Indexable-
let a = "01234"
print(a[0]) // 0
print(a[0...4]) // 01234
print(a[...]) // 01234
print(a[..<2]) // 01
print(a[...2]) // 012
print(a[2...]) // 234
print(a[2...3]) // 23
print(a[2...2]) // 2
if let number = a.index(of: "1") {
print(number) // 1
print(a[number...]) // 1234
}
if let number = a.index(where: { $0 > "1" }) {
print(number) // 2
}
Je ne sais pas quelle version l'a introduit, mais dans Swift 4.2, vous pouvez facilement convertir les deux.
Pour convertir Range<String.Index>
en NSRange
:
let range = s[s.startIndex..<s.endIndex]
let nsRange = NSRange(range, in: s)
Pour convertir NSRange
en Range<String.Index>
:
let nsRange = NSMakeRange(0, 4)
let range = Range(nsRange, in: s)
N'oubliez pas que NSRange
est basé sur UTF-16, alors que Range<String.Index>
est basé sur Character
. Par conséquent, vous ne pouvez pas simplement utiliser des comptes et des positions pour convertir entre les deux!
Vous pouvez utiliser cette fonction et l'appeler chaque fois que vous avez besoin d'une conversion.
extension String
{
func CnvIdxTooIntFnc(IdxPsgVal: Index) -> Int
{
return startIndex.distanceTo(IdxPsgVal)
}
}