Почти все современные механизмы регулярных выражений поддерживают нумерованные группы захвата и обратные ссылки с нумерацией. С длинными регулярными выражениями, содержащими множество групп и обратных ссылок, может быть трудно работать. Их особенно сложно поддерживать, поскольку добавление или удаление группы захвата в середине регулярного выражения нарушает нумерацию всех групп, следующих за добавленной или удалённой группой.
Языки или библиотеки, такие как Python, механизм preg в PHP и языки .NET, поддерживают захваты в именованные местоположения, которые мы называем именованными группами захвата. Одним из наиболее важных преимуществ NCG является то, что присвоение отдельного имени каждой группе захвата может сделать код менее запутанным для тех, кто будет читать его позже (возможно, для вас самих через шесть месяцев), и им не придётся гадать, какая именно цифра соответствует какой группе захвата.
Именованные группы захвата — это замечательно. NSRegularExpression
их не поддерживает.
Реализация NSRegEx
в Cocoa, согласно официальной документации Apple, основана на реализации регулярных выражений ICU:
В настоящее время поддерживается синтаксис, указанный ICU. Регулярные выражения ICU описаны на сайте http://userguide.icu-project.org/strings/regexp.
На этой странице (на http://site.icu-project.org) утверждается, что именованные группы захвата теперь поддерживаются с использованием того же синтаксиса, что и регулярные выражения .NET:
(?...) Именованная группа захвата. <Угловые скобки> являются литералами — они появляются в шаблоне.
например:
\b**(?\d\d\d)-(?\d\d\d)-(?**\d\d\d\b)
Однако собственная документация Apple для NSRegEx
не перечисляет синтаксис для именованных групп захвата, он появляется только в собственной документации ICU, предполагая, что NCG были добавлены недавно и, следовательно, реализация Cocoa ещё не интегрировала их.
То есть единственный способ сопоставления результатов группы, предоставляемый NSRegEx
, в настоящее время — это использование метода rangeAt(:_)
в классе NSTextCheckingResult
, который основан на нумерации. Ну же, Cocoa.
Библиотека расширений NSRegExNamedCaptureGroup призвана предоставить разработчикам, использующим NSRegEx
, интуитивно понятный подход к работе с именованными группами захвата в своих регулярных выражениях.
Carthage:
Если вы используете Carthage для управления зависимостями:
Cartfile
:github "TorinKwok/NSRegExNamedCaptureGroup" ~> 1.0.0
Нажмите File
-> Add Files to "$PROJECT_NAME"
в меню панели Xcode. Выберите NSRegExNamedCaptureGroup.xcodeproj
.
Включите NSRegExNamedCaptureGroup на панели General
.
CocoaPods:
Чтобы установить с помощью CocoaPods, добавьте следующее в ваш проект Podfile:
pod 'NSRegExNamedCaptureGroup', '~>1.0.0'
Swift Package Manager:
Swift Package Manager — это инструмент для управления распространением кода Swift. Он интегрирован со встроенной системой сборки Swift для автоматизации процесса загрузки, компиляции и связывания зависимостей. Как использовать библиотеку NSRegExNamedCaptureGroup
Чтобы добавить зависимость, достаточно добавить её в значение dependencies вашего файла Package.swift.
dependencies: [
.Package( url: "https://github.com/TorinKwok/NSRegExNamedCaptureGroup.git", majorVersion: 1 )
]
Или, если вы используете менеджер пакетов swift-tools-version:4.0, добавьте следующее в массив dependencies в вашем файле «Package.swift»:
.package( url: "https://github.com/TorinKwok/NSRegExNamedCaptureGroup.git", majorVersion: 1 )
Git Submodule:
git submodule add https://github.com/TorinKwok/NSRegExNamedCaptureGroup.git "$SRC_ROOT" --recursive`
import NSRegExNamedCaptureGroup
let phoneNumber = "202-555-0136"
// Regex с именованной группой захвата.
// Без импорта NSRegExNamedCaptureGroup вам пришлось бы иметь дело с результатами сопоставления (экземплярами NSTextCheckingResult)
// через передачу API группы захвата по номеру: rangeAt(:_) ряд магических чисел: 0, 1, 2, 3 ...
// Это довольно неудобно, запутанно и, как следствие, чревато ошибками.
let pattern = "(?<Area>\\d\\d\\d)-(?:\\d\\d\\d)-(?<Num>\\d\\d\\d\\d)"
let pattern = try! NSRegularExpression(pattern: pattern, options: [])
let range = NSMakeRange(0, phoneNumber.utf16.count)
Работа с удобным методом первого совпадения NSRegEx:
let firstMatch = pattern.firstMatch(in: phoneNumber, range: range)
// Гораздо лучше...
// ... чем вызывать rangeAt(1),
print(NSStringFromRange(firstMatch!.rangeWith("Area")))
// выводит "{0, 3}"
// ... чем подвергать свою программу риску получить неожиданный результат, передавая rangeAt(2), когда вы забываете, что средняя группа захвата (?:\d\d\d) заключена в пару группирующих скобок, что означает, что она вообще не будет участвовать в захвате.
//
// И наоборот, в случае использования метода расширения NSRegExNamedCaptureGroup rangeWith(:_), мы получим диапазон {NSNotFound, 0}, когда указанная группа имён не существует в исходном регулярном выражении.
print(NSStringFromRange(firstMatch!.rangeWith("Exch")))
// группы захвата с именем "Exch" не существует, поэтому выводится "{9223372036854775807, 0}"
// ... чем передавать rangeAt(2)
print(NSStringFromRange(firstMatch!.rangeWith("Num")))
// выводит "{8, 4}"
Работа с основанным на блочном перечислении API NSRegEx:
pattern.enumerateMatches(in: phoneNumber, range: range) {
match, _, stopToken in
guard let match = match else { return }
print(NSStringFromRange(match.rangeWith("Area")))
// выводит "{0, 3}"
print(NSStringFromRange(match.rangeWith("Exch")))
// группы захвата с именем "Exch" не существует
// выводит "{9223372036854775807, 0}"
print(NSStringFromRange(match.rangeWith("Num")))
// выводит "{8, 4}"
}
Работа с основанным на массиве API NSRegEx:
let matches = pattern.matches(in: phoneNumber, range: range)
for match in matches {
print(NSStringFromRange(match.rangeWith("Area")))
// выводит "{0, 3}"
print(NSStringFromRange(match.rangeWith("Exch")))
// группы захвата с именем "Exch" не существует
// выводит "{9223372036854775807, 0}"
print(NSStringFromRange(match.rangeWith("Num")))
// выводит "{8, 4}"
}
⚠️
Это экспериментальная предварительная обработка для реализации регулярного выражения Cocoa. Вполне вероятно, что я что-то сломал или каким-то образом проигнорировал лучший вариант. Не стесняйтесь создать проблему на GitHub, если у вас возникнут проблемы или есть предложения по лучшему подходу.
Автор: Торин Квок.
Лицензия: Apache-2.0.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )