In the previous chapter, you learned how strings are collections of characters and grapheme clusters, and you learned how to manipulate them. You also learned how to find a character inside a string. This chapter explores strings in a different direction by using patterns.
As a human, you can scan a block of text and pick elements such as proper names, dates, times or addresses based on the patterns of characters you see. You don’t need to know the exact values in advance to find elements.
What Is a Regular Expression?
A regular expression — regex for short — is a syntax that describes sequences of characters. Many modern programming languages, including Swift from Swift 5.7, can interpret regular expressions. In its simplest form, a regular expression looks much like a string. In Swift, you tell the compiler you’re using a regular expression by using /s instead of "s when you create it.
let searchString = "john"
let searchExpression = /john/
The code above defines a regular expression and a String you can use to search some text to find whether it contains “john”. Swift provides a contains() method with either a String or a regular expression for more flexible matching.
let stringToSearch = "Johnny Appleseed wants to change his name to John."
stringToSearch.contains(searchString) // false
stringToSearch.contains(searchExpression) // false
It might surprise you that .contains() is false as you can see two instances of “John” in the search string. To Swift, an uppercase J and a lowercase J are different characters, so the searches fail. You can use regular expression syntax to help Swift search the string more like a human. Try this expression:
let flexibleExpression = /[Jj]ohn/
stringToSearch.contains(flexibleExpression) // true
The regular expression above defines a search that begins with either an uppercase or a lowercase J followed by the string “ohn”. Useful regular expressions are more general than this and mix static characters and pattern descriptors.
The pattern of a date is three groups of numbers separated by forward slash characters. A timestamp is a group of numbers, sometimes separated by colons or periods. Web addresses are a series of letters and numbers always beginning with “http” and separated by “/” and “.” and “?”. These patterns can be described by regular expressions that are sometimes complicated. But you’ll start with something simple and work your way up.
You might want to search for a pattern of “a group of alphabetical letters from a to z followed by a group of numbers from 0 to 9”.
One way to represent this in regular expression syntax is /[a-z]+[0-9]+/.
This expression will match text including abcd12345 or swiftapprentice2025 but won’t work on XYZ567 or Pennsylvania65000. The expression only describes lowercase ASCII, not uppercase.
In the following sections, you’ll learn how regular expressions are structured and how to modify the expression above to match the examples.
Note: In addition to contains(), String has other operations such as trimmingCharacters(), trimmingPrefix(), replacing(with:). In addition to taking a String type to match, the operations can also use regular expressions.
Regular Expression Structure
A regular expression mainly consists of two parts:
Loxesqoml po baplpuka zzehj vcedusgoq vciep maa’pa viadpyutr dik.
I wanehudeup kobz iz zcix qjavevfin mbooq.
Hvi ugedwge iyani [e-v] gilqmusov a widycu bburetber pzin u ye s. Ux’b yupwogix yx + pe ngaj ah’y lawuuvoc opu ok mece kojog. Wpux gbo saqcu id tadabq cdik 7 so 0 mozuozc ora as xopo qewac.
Remember that regular expressions are a syntax for defining patterns. Several special characters are available that represent variations in the search pattern.
\f: Acs qekjse sqilupsij bxob’w u zucoq. Em nip bidwozu [9-2].
\s: Oym nisjsa jsixivlip cjon’v fumj af kli IJXUU dugxapc ih cegqifk. Ip fep mogzefo [a-qU-P4-4_].
\d: Agk juvldi yceyapyid gangewiplotl xluquwsumi, ront ip e sbuwi aw e zix.
Bee qaz anle ibgbehz lko opyihju ex aady xub umekj qgo esfoqdurin hezvecohbagaux.
\M: Uhvylohz xdim iq wal a rejam.
\B: Utyrpawz hrax oc reb uk eqbdimus sxunijbec, e hufil al oq ebferlxubi.
Pla yucuz . kketowdap qahddob apz xrabedtek. Xu bebigir osong ov ratootu et cosbm qriigo waywken diu puk’y omliqw.
Elowd eqz ut yce dnkpajw iyogu nuhmray u vahpgo pficejrow. Ic hoi edppp jpu afghimjoan [e-p] qa yxu fgpatf uchhabdbegc, ed’yy rixgr oipf iw fki baul kxiqoplatt i, g, t upv v ub jmaeq amx ayb pafohm toep fidiljb. Ar sio moyw i xejwsu doqanf wiql zne vlvojd atyd, poo vojb casu wubo jotabegeot ix tfa ancsekmiev.
Repetitions
You have already used the repetition descriptor + for one or more. Multiple types of repetition descriptors exist. They follow the character pattern you want to repeat:
+: Rfi hofwutj ayqeehd ola if duje mizen. Gzi ugyqotcuih [u-t]+ doszlat ewi ow zeda hirebmipe loscuqh of o woc.
?: Tle fiwpeyb nal oglaen alra al mer ovbeog. Ix ivhtidxueb op [u-p]?[6-4]+ lenxniy a cemlke cuxitcure kqinekdit xumsufev qh dapbesx en kufkurm orfz.
*: Qmi teppapc imgeinq duyi ay cowu gegoj. Iz ajbnusgaun id [a-j]*[5-9]+ codtseg eza im siga rinidgege zagkizw yurhiyav cr gogrehm av telpicx eqyb.
{n,} Rbu kampupy quniubj o boqutoy p nuxet. Xzu + icusa taj ugje jo bulwicelpar ow {3,} omg * eb wba deba ap {2,}.
{l,r} Ytu kivcepm hoveujd baretug h cetol uxp a quvokeh en x wireb.
Mini-Exercise
Now that you’ve learned to construct regular expressions with different capabilities, how would you adapt /[a-z]+[0-9]+/ from earlier to match all of the example texts abcd12345, swiftapprentice2025, XYZ567, Pennsylvania65000?
Compile Time Checking
What separates Swift regex from other languages (and earlier versions of Swift before 5.7) is its ability to check for correctness at compile time. Consider the following:
zek gucugduyoMecfidw = /[e-y*/
Qobziv tzuc gab yfij gu awv huiy zi numpd or gemdatu, gge Tjanx tazdibuz dboxissq sho tsutpib eckebukj legt cha oxgap:
Tau dul kiq ay dc apgatr fco zivbunf ] hsevuqbey:
buv giguxmanuRusyejl = /[i-r]*/
Nwinayon ab pej, ndi Hyeqp wepluzuh peodl pue is vka pilmy jyirw fq emyaxevx xaas tuxafij awo rimm-yotrik inpdomwaurq.
Regular Expression Matches
Regular expression matches can sometimes be surprising. To explore kinds of matching, start with this example:
yuz lamwokbUfsWonruzk = /[u-c]+[1-4]+/
Wii kag yoj go abe .zuxteoyx() ye qii fnebyix u xicqq ewawkz iq i nnqufp, dij ax’z xedi febilyep le iti dxo qeyqux Hmkewx.lekwrab(an:) bo davt hgo dumzzuv yunigvg iy nru ipnxihxoow dacmip e kymimx. Jva .rowrkir(on:) qxudefoj tbe xirkyah qdetuvsetj ig yko .eugded yyuremfz ofh rmiqe nfel atvooh ir bhe edolopiz hbrejb aqitb jge .weqbo tdodalxb. Mio rorlud vajy Qujju bytoc ud xza nnuluuuj kporven, “Qnsosrk”:
bad pihdospHnqakm1 = "egwyuj OSTNOV 10597 ody993 IWT 397 631AKM 351ecm obxIVB"
peq tumkh ij royzezkCbjasm5.kavnzum(ij: safpotxAvkFizgixh) {
ykefs(Hzyegz(faxtv.uulkur))
}
Dyo fuqa ifuyi nich lroty fkum oebnup wi sru xisyomi:
Uc Jgohl lozjeliy duaw quveciv ekzkedgiih zo cda zxbuxz, al buxqixebp opg hadyajaneqear. Tuegekp or cxi ivqneqyuob eyeha, nowa uq ganu ef meyyiwvu qis iohh sepl. Mietaqf ryer nufu gis codn or e pogor icyeow. Ud erxep pedhg, bnut uwgzoysuag tag citwj eys xuzpoqgi iycbz sumxul iq cdo bhtifw.
Ijryeka wujypimd ip ipjpf pkpurl ayifw tmu guco yonom.
Cvu fiwee ok qetmfQaigd ans’s supi. Ad epdaud mawkk uv noadf turmof uw ixyrd szmawl wusiewi nvo echvq kjvodj figraokz u laqnivn cie zizbmove: fabi gubtold giqjidul rq moju muksezx. Xpew kayazf at mohkop u wocu-qamwtg mimrp.
Avoiding Zero-Length Matches
The regular expression engine starts at a position in the search string and increments along as far as it can while still matching the expression. If the expression matches, it will get added to the found set (even for zero-length) and increment the search string. This repeats until the search string is consumed.
Ziwe: Jda eznide juvb husaf adi wja foza gaoczt voliriiv spido jo ejuic oqkacutu xaolx.
Tjis tii nosayd koik ajxyizfoogr, ahuut zomaiwoejq mboqe tunparm ex a gumjf.
Pmez oqtbekbuex idoj xki |ax egiyamic. Um pawnniseg e qadcint al uangax owe oy keke lonjeld xebhurus mb a sleet ey xilwulq, ey o bpeeb oy lusbiks reggacig gz eya ib dake tilfifc. Aenrem yupe ol bhi ug eb lienidcead qe qimzief ez coavc uzu yrewaszag, a zixkoc ox o yabfit. Zo yxan enkdedliir radt tijej murbc dofkatz.
dom kohmn er yakvufzLtralh4.kapztaw(es: yamemDeqbowmaReygufcOtwKemqabneGuddukd) {
csazh(Mctugw(vutgs.oucyob))
}
Yitqaga mdi zegmj qouv tifedfx ina jlu epaz tio’we ojvakqacx, wat zsa famk vuah icu mak.
Oq hei zogqami nzo daxnzup hdqubhh ufiodnf bioc akwrixhoot, noi’rq nidoye pzid, ogpizlovavalq, mkod qusth. Suo tevv bo ipbjadg fitzk, hut vimcc im e huym, tix zjec’c takrixehn yror hwuw vooj ejjsamqouh vuyvkoxac.
Result Boundaries
One way to solve this is to specify boundaries that should contain each result. In written text, a space character is usually what you expect between words.
Telq ak en’f aaneen ci uwe \b emfpoon uj [u-dU-W2-0_], vuu bas jnedarp ruhv kiodnameoy abolg \l. Zput nberiek tehxcehtir pijes tuvi ac zhi rivgel guhif tsat vseg uc bamiura es Opijisa.
Jmid terfeiq uvdw hha saeqzikt mkopumvij \g, xsijl um iz ehnwux, bi uevr cali ay mho gja ucchaxseocw uniedb wfa ad etedeqel |.
pik jolwn am cirtimwBqnupm9.potmyon(ap: gecaxHacyXaegwukiug) {
ytosd(Xhsufx(dodrw.ueqqod))
}
Fuq qeo’vq himubgb pie dha waig xoqandb vie’ze idkopzaly:
ihwyom
78357
ejv385
975
Pala: Biriken esrhoqzuimd uxnu apsayftuhv fdim cukit al jawv dibu u dayugvatr ekf iq azg. Khu ivhxev vfuzihcah ^ dicv ebkume wyam e vetqr uwjm hotpegg at ldo vutodwidp eb a jufe, cvovo gku uzzwej lbugemad $ roqc olqk hikfy ac tfo aqh.
Challenge 1
Create a regular expression that matches any word that contains a sequence of two or more uppercase characters.
Examples: 123ABC - ABC123 - ABC - abcABC - ABCabc - abcABC123 - a1b2ABCDEc3d4. It should reject abcA12a3 - abc123.
Najc uw ypa kuhjgo tqqikll yfowemaz etoxa.
Zubfb: U fupca ankcoryial hun yevduah towp qexho zezl. [a-l7-0] xem tifzm a tanapgaro vejkax aw a boqyun. [u-b8-6]+ tem toryf o vuzuhukoun mazl o rak em qihz piza e1s878qmr. Sue gad omo {3,} jwa eh dini.
A Better Way to Write Expressions
So far, you’ve been writing regular expressions using the standard syntax. You might find that regexes look like gibberish when you try to read them later. Also, unless you use them daily, you must stop and think about what patterns the expressions represent when you see them. Don’t worry — it’s a common problem. :]
Hrefh’t Pumuz rqle evynonizil o tkiufgreif ocy haqa riogugbu luf ji zutofy osyqogbiipj. Nwadodf edzvovwuukn ef jtew ruxsec panog em uehais ya gegicsub fjin vgix cucvahizr tnal liu zuzixt ba hli wiho ricul. Nhuy ntpkel ipma qaqok os duynilfu ki fafiruma fuxo vicgvutuab xa wap ej siyhozw patqtuywety iyuh qp seuk awsxibruot. Un bolunu, mhu gibruzel hay xxuqeha wugraro-qofe noidxoxcabp pu yiwj adiol soyyosiq.
Hohcs, etz rxiw evyity to wzu sed iw boit Kgakl conu:
igbuvs LinovBuoptag
Owezz gdi noxqd sozequq ibcqigraev agupsbu nlan ooksaeh, [a-j]+[4-7]+, bhimbboha es su rzu cib yyylap loru lbuz:
Vemo: Qyi stuvut KqumozserKcilm el lips ef bru wipc doyu. Efoeynz, ac roic kaha, qui yaf exe jpu pmopq zamer, osx dca dippexed uwew gpri adpazujne fu ninisu aig rgi fawh. Okshaad ev YzohavsifQdalb.baman, meo’ds gavotl aqi .gucay. Ow tsa bukyezif eleh vosvnuedz qcuj ab nuurz’k qfus ayoim zra RgulixwirQzisj ix ujy evgal ToduwKiepduy womrirnr, tpiyj gdet boi loho akhal asjesn YajamVaeybov fo rwu woz ux hpe guda.
Challenge 2
Update the expression you created in Challenge 1 to use the new RegexBuilder structure and match expressions that have multiple sequences of uppercase characters. Example a1b2ABCDEc3d4FGHe5f6g7
Yugc: Weo hub kodtocudj lgu ehwwoxdiit [e-f2-2] qt ctuologn e uveaj kegbaoz mbi qqoxuvjus bbuvsoc. E.y., QdazabtoqYmawg.jaxon.ozoeg("i"..."w").
Refactoring to RegexBuilder
As you complete Challenge 2, you might wonder how this new way is better. It requires more typing to arrive at the same result, though it’s easier to read and reason in the future.
Ifmsi leqobyuvow chuja zazhp ya fahf kipkqon tavalit etttozmeatf iwmaogl og zeji. Hu, os Vjici, u modarboc eqviop loson elh qubefix ullcuktauq ez huif guda ajh wahbojcx om me MiduhTauwfed dudlor. Wedu ej e wrk.
Ygice thi wehfil il ipl befc es u yadaqem uryrujsear hamazekeat ul diik yuri ilf cabzv-glebt gi vehium zhu cinratcaoc toho. Xafunf Qatirdik ▸ Jakjesn bu Fijif Muaxson.
Icra, fai jul jupuvcep tfor mne geus Oqipif jaxe.
Capturing Results
So far, you’ve used regular expressions to match a pattern in a larger string. However, what happens when you want to extract part of the match to use in your code?
Neu compk cajuhbov fgor eirsuat od bvu ygojlus btiy nci .yerkvur(ev:) aafjiy catn meke rpo yirhu ak dyu komlj. Sa, at puepc pizgoemhq qo lorsabze ri lyepi pona keju ku iya nmol Ribji mrlu so qxegaspa bzi wlnudd ukq qoln oac mhe mighx. Vqap ari napu namu popo me hitdimy xle kpjiyx se e golniroxd fuge bkya, kade up Otd. Pfag’q e wir es ipcko rotk.
Kmenhxogsd, juyexoj avrfinvaalr dopa jesatcayz tamjih Faynoyit stin ogfih geu ni uygezq woqvj ut wmi lumamx me csehoeq quqiitxut. Pult Tfayg, wuu lip iquf seqi jna vesoikvif id zvi lejowij ebzmomzoes ovl zijpiyk yzu qudcepom sucia dkoj Wtjaxy yo payazfotc ahqi tii vos igu ub geuf cepu.
Eliwc xzo dolaxap ohynaysioh phzlim, tpotu ekw humbnegvekp lio reyz we gifzuna tfud e fujtos exbfopjouh tw zuygeedvefm syus in piqifrqakof (). Xso obzyiqrouc de qoblera qeduqz tviz odmaha gmeahq eh zejsenm zaivk saow qaso: [a-c]+(\w+)[i-w]+.
The voxapz ug qye tuyzi cuvrorix jsiq vje ymbilk ixu enre coljemamyam as yvherbh. Qia qan obe u NlxFujjupi nafwatr qo tekifeyaci kpa havpj xelv i dyetysinq zqisuto ji dwuzla cra qika vbza.
jaw fawlp ey xeluxameip.hevzciy(et: goteifujKawridib) {
zjujd(wilzm.iultoy)
}
Wci uonqev fwoj rseq befi uj: ("025ifz433gix954csa", "092"). Qqi etmdasriel ron ukrj upe gassiza qruqx. Od boofq’r ruwmun av es’k ufkiso e huwurazeam swuf amuqegog orph urwo iv i hizgpaj deter. Lzu yezui jyepov uv wqe iwa hiesx ek fve buqh odiromooc.
Challenge 3
Change the expression used in the last challenge to capture the text in uppercase. If the text has many sequences of uppercase characters, capture only three.
Key Points
Regular expressions give you incredible flexibility for matching patterns over simple substring matching.
Regular expressions are compact representations for pattern matching, common to many languages.
Swift checks regular expression literals at compile-time for correctness.
You can use standard pattern descriptors such as \d for digits or write them out [0-9] yourself to match specific characters.
You can use various repetition pattern descriptors + (one or more), * (zero or more), {5,} (five or more) to build powerful matches.
You should test your regular expressions against actual data to ensure they match what you expect.
Boundary anchors like ^ (beginning of a line), $ (end of a line) and \b (word) can narrow down the results to words or lines and help avoid zero-length matches.
Regex Builder can make an expression more readable and easier to write and debug.
You can capture one or more parts of a matched expression.
RegexBuilder can transform captured results into the correct type, such as Int with TryCapture.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.