Programmiersprachen: Reguläre Ausdrücke in Swift neu aufgestellt
Seite 2: Baukasten für reguläre Ausdrücke
Sogar kürzere reguläre Ausdrücke können kryptisch sein und ein Nachschlagen in der Dokumentation erfordern. Die Logik erst in einem String oder einem Regex Literal zu kodieren, um sie anschließend wieder zu analysieren, ist zudem nicht der direkte Weg.
Reguläre Ausdrücke eignen sich hervorragend für eine domänenspezifische Sprache (DSL). Swift bringt hierfür in der Standard Library einen ResultBuilder
im Modul RegexBuilder
mit. Damit lassen sich reguläre Ausdrücke ähnlich bequem und lesbar zusammenbauen wie eine View
in SwiftUI
, das dafür den ViewBuilder
eingeführt hat.
Bevor ein Swift-Programm den RegexBuilder
verwenden kann, muss es ihn importieren:
import RegexBuilder
let regex = Regex {
"b"
Capture {
ZeroOrMore(.any)
}
"d"
}
if let match = "abcde".firstMatch(of: regex) {
let (matched, detail) = match.output
print(matched) // "bcd"
print(detail) // "c"
}
Formatierte Daten erkennen
Der RegexBuilder
ermöglicht es, Teile eines regulären Ausdruckes auszulagern, um ihn modularer und lesbarer zu gestalten.
Ein Beispiel dafür sind die Formatter
aus dem Framework Foundation
. Sie kodieren und dekodieren Daten wie Fließkommazahlen und Zeitangaben in einem String. Apple hat die Formatter
für den Einsatz in den neuen regulären Ausdrücken erweitert:
import Foundation
import RegexBuilder
let regex = Regex {
"Datum: "
Capture {
One(.date(.numeric,
locale: Locale(identifier: "de_DE"),
timeZone: .current))
}
}
if let match = "Datum: 11.06.2022".firstMatch(of: regex) {
let (matched, detail) = match.output
print(matched) // "Datum: 11.06.2022"
print(detail) // 2022-06-10 22:00:00 +0000
}
Die Debug-Ausgabe mittels print()
verwendet GMT als Zeitzone, womit das Ergebnis dem erwarteten 11.06.2022 00:00 MESZ entspricht.
Der Output
ist (Substring, Date)
. detail
ist somit tatsächlich ein Date
und kein Substring
.
Modularisieren
Mit dem RegexBuilder
lassen sich zudem eigene Teile lokal auslagern:
import Foundation
import RegexBuilder
let label = Regex {
"Datum: "
}
let captureDate = Regex {
Capture {
One(.date(.numeric,
locale: Locale(identifier: "de_DE"),
timeZone: .current))
}
}
let regex = Regex {
label
captureDate
}
if let match = "Datum: 11.06.2022".firstMatch(of: regex) {
let (matched, detail) = match.output
print(matched) // "Datum: 11.06.2022"
print(detail) // 2022-06-10 22:00:00 +0000
}
Um Teile regulärer Ausdrücke wie obiges label
an anderer Stelle und in anderen Projekten weiterzuverwenden, kann man sie als eigene struct
s auslagern.
import Foundation
import RegexBuilder
struct Label: RegexComponent {
@RegexComponentBuilder var regex: Regex<(Substring)> {
"Datum: "
}
}
let captureDate = Regex {
Capture {
One(.date(.numeric,
locale: Locale(identifier: "de_DE"),
timeZone: .current))
}
}
let regex = Regex {
Label()
captureDate
}
if let match = "Datum: 11.06.2022".firstMatch(of: regex) {
let (matched, detail) = match.output
print(matched) // "Datum: 11.06.2022"
print(detail) // 2022-06-10 22:00:00 +0000
}
Weiterführende Informationen finden sich in den Videos der beiden Sessions von Apples Entwicklerkonferenz WWDC 2022 zu regulären Ausdrücken: