Даже если matchesInString()
метод принимает в String
качестве первого аргумента a , он работает внутренне NSString
, и параметр диапазона должен быть задан с использованием NSString
длины, а не длины строки Swift. В противном случае произойдет сбой для «расширенных кластеров графем», таких как «флаги».
Начиная с Swift 4 (Xcode 9), стандартная библиотека Swift предоставляет функции для преобразования между Range<String.Index>
и 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 []
}
}
Пример:
let string = "🇩🇪€4€9"
let matched = matches(for: "[0-9]", in: string)
print(matched)
// ["4", "9"]
Примечание . Принудительное развертывание Range($0.range, in: text)!
является безопасным, поскольку NSRange
ссылается на подстроку данной строки text
. Однако, если вы хотите избежать этого, используйте
return results.flatMap {
Range($0.range, in: text).map { String(text[$0]) }
}
вместо.
(Более старый ответ для Swift 3 и ранее :)
Таким образом, вы должны преобразовать данную строку Swift в a, NSString
а затем извлечь диапазоны. Результат будет автоматически преобразован в массив строк Swift.
(Код для Swift 1.2 можно найти в истории редактирования.)
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 []
}
}
Пример:
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 []
}
}
Пример:
let string = "🇩🇪€4€9"
let matched = matches(for: "[0-9]", in: string)
print(matched)
// ["4", "9"]
Мой ответ основан на данных ответах, но делает сопоставление регулярных выражений более надежным, добавив дополнительную поддержку:
do/catch
печати на консоль и используетguard
конструкциюmatchingStrings
как расширениеString
Swift 4.2
Swift 3
Swift 2
источник
try?
может использоваться, если вас интересует только исход вызова, а не сообщение о возможной ошибке. Так что да,guard try? ..
хорошо, но если вы хотите напечатать ошибку, вам нужен do-block. Оба способа Swifty.Если вы хотите извлечь подстроки из строки, а не только из позиции (но фактическую строку, включая эмодзи). Тогда следующее, возможно, более простое решение.
Пример использования:
Вернет следующее:
Примечание, используя "\ w +", может привести к неожиданному ""
Вернет этот массив строк
источник
Я обнаружил, что решение для принятого ответа, к сожалению, не компилируется в Swift 3 для Linux. Вот модифицированная версия, которая делает:
Основными отличиями являются:
Swift в Linux, кажется, требует удаления
NS
префикса для объектов Foundation, для которых нет собственного эквивалента Swift. (См. Предложение Swift Evolution № 86. )Swift в Linux также требует указания
options
аргументов как дляRegularExpression
инициализации, так и дляmatches
метода.По какой - то причине, понуждения
String
вNSString
не работает в Swift на Linux , но инициализирует новыйNSString
сString
как источник работает.Эта версия также работает со Swift 3 в macOS / Xcode, за исключением того, что вы должны использовать имя
NSRegularExpression
вместоRegularExpression
.источник
@ p4bloch Если вы хотите захватить результаты из серии скобок захвата, вам нужно использовать
rangeAtIndex(index)
методNSTextCheckingResult
вместоrange
. Вот метод @MartinR для Swift2 сверху, адаптированный для захвата скобок. В возвращаемом массиве первым результатом[0]
является весь захват, а затем начинаются отдельные группы захвата[1]
. Я закомментировалmap
операцию (чтобы было легче увидеть, что я изменил) и заменил ее вложенными циклами.Пример использования может быть, скажем, вы хотите разделить строку,
title year
например, «В поисках Дори 2016», вы можете сделать это:источник
[String?]
и вfor i in 0..<result.numberOfRanges
блоке вы должны добавить тест, который добавляет соответствие, только если диапазон! =NSNotFound
, В противном случае он должен добавить ноль. См .: stackoverflow.com/a/31892241/2805570Swift 4 без NSString.
источник
NSMakeRange(0, self.count)
это не правильно, потому чтоself
этоString
(= UTF8), а неNSString
(= UTF16). Таким образом,self.count
это не обязательно так же, какnsString.length
(как используется в других решениях). Вы можете заменить расчет диапазона наNSRange(self.startIndex..., in: self)
Большинство приведенных выше решений дают полное совпадение, игнорируя группы захвата, например: ^ \ d + \ s + (\ d +)
Чтобы получить совпадения группы захвата, как ожидалось, вам нужно что-то вроде (Swift4):
источник
for index in 0..<matches.count {
вокругlet 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)) } }
Вот как я это сделал, я надеюсь, что это даст новый взгляд на то, как это работает на Swift.
В этом примере ниже я получу любую строку между
[]
источник
Это очень простое решение, которое возвращает массив строк с совпадениями
Свифт 3.
источник
Самый быстрый способ вернуть все совпадения и захватить группы в Swift 5
Возвращает 2-мерный массив строк:
возвращается ...
источник
Большое спасибо Ларсу Блумбергу за его ответ за сбор групп и полные матчи со Swift 4 , которые мне очень помогли. Я также сделал дополнение к нему для людей, которые хотят получить ответ error.localizedDescription, когда их регулярное выражение недопустимо:
Для меня наличие localizedDescription как ошибки помогло понять, что пошло не так с экранированием, так как оно показывает, какой последний regex swift пытается реализовать.
источник