Même si la matchesInString()
méthode prend a String
comme premier argument, elle fonctionne en interne avec NSString
, et le paramètre range doit être donné en utilisant la NSString
longueur et non comme la longueur de la chaîne Swift. Sinon, il échouera pour les «clusters de graphèmes étendus» tels que les «indicateurs».
Depuis Swift 4 (Xcode 9), la bibliothèque standard Swift fournit des fonctions pour convertir entre Range<String.Index>
et NSRange
.
func matches(for regex: String, in text: String) -> [String] {
do {
let regex = try NSRegularExpression(pattern: regex)
let results = regex.matches(in: text,
range: NSRange(text.startIndex..., in: text))
return results.map {
String(text[Range($0.range, in: text)!])
}
} catch let error {
print("invalid regex: \(error.localizedDescription)")
return []
}
}
Exemple:
let string = "🇩🇪€4€9"
let matched = matches(for: "[0-9]", in: string)
print(matched)
// ["4", "9"]
Remarque: le dépliage forcé Range($0.range, in: text)!
est sûr car le NSRange
fait référence à une sous-chaîne de la chaîne donnée text
. Cependant, si vous voulez l'éviter, utilisez
return results.flatMap {
Range($0.range, in: text).map { String(text[$0]) }
}
au lieu.
(Ancienne réponse pour Swift 3 et versions antérieures :)
Vous devez donc convertir la chaîne Swift donnée en un NSString
, puis extraire les plages. Le résultat sera automatiquement converti en un tableau de chaînes Swift.
(Le code de Swift 1.2 se trouve dans l'historique des modifications.)
Swift 2 (Xcode 7.3.1):
func matchesForRegexInText(regex: String, text: String) -> [String] {
do {
let regex = try NSRegularExpression(pattern: regex, options: [])
let nsString = text as NSString
let results = regex.matchesInString(text,
options: [], range: NSMakeRange(0, nsString.length))
return results.map { nsString.substringWithRange($0.range)}
} catch let error as NSError {
print("invalid regex: \(error.localizedDescription)")
return []
}
}
Exemple:
let string = "🇩🇪€4€9"
let matches = matchesForRegexInText("[0-9]", text: string)
print(matches)
// ["4", "9"]
Swift 3 (Xcode 8)
func matches(for regex: String, in text: String) -> [String] {
do {
let regex = try NSRegularExpression(pattern: regex)
let nsString = text as NSString
let results = regex.matches(in: text, range: NSRange(location: 0, length: nsString.length))
return results.map { nsString.substring(with: $0.range)}
} catch let error {
print("invalid regex: \(error.localizedDescription)")
return []
}
}
Exemple:
let string = "🇩🇪€4€9"
let matched = matches(for: "[0-9]", in: string)
print(matched)
// ["4", "9"]
Ma réponse s'appuie sur les réponses données mais rend la correspondance regex plus robuste en ajoutant un support supplémentaire:
do/catch
en n'imprimant pas sur la console et utilise laguard
constructionmatchingStrings
en tant qu'extension àString
Swift 4.2
Swift 3
Swift 2
la source
try?
peut être utilisé si vous n'êtes intéressé que par le résultat de l'appel, pas par un éventuel message d'erreur. Donc oui,guard try? ..
c'est bien, mais si vous voulez imprimer l'erreur, vous avez besoin d'un do-block. Les deux moyens sont Swifty.Si vous souhaitez extraire des sous-chaînes d'une chaîne, pas seulement la position (mais la chaîne réelle, y compris les émojis). Ensuite, ce qui suit peut-être une solution plus simple.
Exemple d'utilisation:
Renverra ce qui suit:
Notez que l'utilisation de "\ w +" peut produire un "" inattendu
Renverra ce tableau de chaînes
la source
J'ai trouvé que la solution de la réponse acceptée ne se compile malheureusement pas sur Swift 3 pour Linux. Voici donc une version modifiée qui fait:
Les principales différences sont:
Swift sous Linux semble nécessiter la suppression du
NS
préfixe sur les objets Foundation pour lesquels il n'y a pas d'équivalent natif Swift. (Voir la proposition d'évolution Swift n ° 86. )Swift sur Linux nécessite également de spécifier les
options
arguments pour l'RegularExpression
initialisation et lamatches
méthode.Pour une raison quelconque, forcer a
String
dans unNSString
ne fonctionne pas dans Swift sur Linux mais initialiser un nouveauNSString
avec aString
comme source fonctionne.Cette version fonctionne également avec Swift 3 sur macOS / Xcode à la seule exception que vous devez utiliser le nom à la
NSRegularExpression
place deRegularExpression
.la source
@ p4bloch si vous souhaitez capturer les résultats d'une série de parenthèses de capture, vous devez utiliser la
rangeAtIndex(index)
méthode deNSTextCheckingResult
, au lieu derange
. Voici la méthode ci-dessus de @MartinR pour Swift2, adaptée pour les parenthèses de capture. Dans le tableau renvoyé, le premier résultat[0]
est la capture entière, puis les groupes de capture individuels commencent à partir de[1]
. J'ai commenté l'map
opération (il est donc plus facile de voir ce que j'ai changé) et l'ai remplacée par des boucles imbriquées.Un exemple de cas d'utilisation pourrait être, disons que vous voulez diviser une chaîne de
title year
par exemple "Finding Dory 2016", vous pouvez faire ceci:la source
[String?]
et dans lefor i in 0..<result.numberOfRanges
bloc, vous devez ajouter un test qui n'ajoute la correspondance que si la plage! =NSNotFound
, Sinon il devrait ajouter nil. Voir: stackoverflow.com/a/31892241/2805570Swift 4 sans NSString.
la source
NSMakeRange(0, self.count)
n'est pas correcte, carself
est unString
(= UTF8) et non unNSString
(= UTF16). Donc, leself.count
n'est pas nécessairement le même quensString.length
(comme utilisé dans d'autres solutions). Vous pouvez remplacer le calcul de la plage parNSRange(self.startIndex..., in: self)
La plupart des solutions ci-dessus ne donnent que la correspondance complète en ignorant les groupes de capture, par exemple: ^ \ d + \ s + (\ d +)
Pour obtenir les correspondances du groupe de capture comme prévu, vous avez besoin de quelque chose comme (Swift4):
la source
for index in 0..<matches.count {
autourlet lastRange... results.append(matchedString)}
for i in 1...lastRangeIndex { let capturedGroupIndex = match.range(at: i) if capturedGroupIndex.location != NSNotFound { let matchedString = (self as NSString).substring(with: capturedGroupIndex) results.append(matchedString.trimmingCharacters(in: .whitespaces)) } }
C'est ainsi que je l'ai fait, j'espère que cela apporte une nouvelle perspective sur la façon dont cela fonctionne sur Swift.
Dans cet exemple ci-dessous, j'obtiendrai la chaîne de caractères entre
[]
la source
C'est une solution très simple qui retourne un tableau de chaîne avec les correspondances
Swift 3.
la source
Le moyen le plus rapide de renvoyer tous les matchs et de capturer des groupes dans Swift 5
Renvoie un tableau bidimensionnel de chaînes:
Retour...
la source
Un grand merci à Lars Blumberg pour sa réponse pour avoir capturé des groupes et des matchs complets avec Swift 4 , ce qui m'a beaucoup aidé. J'ai également fait un ajout pour les personnes qui veulent une réponse error.localizedDescription lorsque leur regex est invalide:
Pour moi, avoir la description localisée en tant qu'erreur m'a aidé à comprendre ce qui n'allait pas avec l'échappement, car il affiche le regex final swift tente d'implémenter.
la source