Hópar og notkun

Hvernig svigar grípa hluta úr texta, hvernig endurraða má texta, og hvernig sama mynstur er notað í R og Python.

Hópar og endurnotkun

Svigar gera tvennt:

  1. þeir hópa hluta af mynstri,
  2. þeir geta gripið textann sem fannst.

Dæmi: línur á sniðinu nafn, netfang.

^(.+),\s*(.+@.+)$
Bútur Merking
^ byrjun línu
(.+) fyrsti hópur: nafn
, komma
\s* núll eða fleiri bil
(.+@.+) einföld hugmynd um netfang
$ endir línu

Hóparnir gera okkur kleift að endurraða texta. Ef línan er:

Helga, helga@hi.is

má breyta henni í:

helga@hi.is Helga

með því að vísa í hóp 2 og svo hóp 1.

AthugasemdEinfalt fyrst, strangt seinna

Það er oft skynsamlegt að byrja á einföldu mynstri sem finnur líkleg tilvik, skoða niðurstöðuna, og herða svo mynstrið. Fullkomið netfangaregex er langt og ólærdómsríkt; fyrir gagnahreinsun er oft betra að nota nógu gott mynstur og skoða undantekningarnar.

Í R og Python

Sama mynstur má nota í mörgum málum. Hér er einfalt dæmi sem finnur netföng í texta.

txt <- c(
  "Hafðu samband við helga@hi.is",
  "Þetta er ekki netfang",
  "Prófun: nemandi.1@example.org"
)

mynstur <- "[\\w._%+-]+@[\\w.-]+\\.[A-Za-z]{2,}"
fundid <- gregexpr(mynstur, txt, perl = TRUE)
regmatches(txt, fundid)
[[1]]
[1] "helga@hi.is"

[[2]]
character(0)

[[3]]
[1] "nemandi.1@example.org"
Aðvörunperl = TRUE — annars finnur R ekkert

R hefur tvær regex-vélar. Sú sjálfgefna er POSIX og þekkir ekki \w, \d\s. Slepptu perl = TRUE og mynstrið hér að ofan skilar character(0) fyrir allar línurnar — engin villa, engin viðvörun, bara tómt svar.

Þetta er sérstaklega lúmskt þegar mynstur er afritað úr Python eða af regex101, því þar eru \w og \d sjálfsögð.

Tveir kostir í boði:

# 1) kveikja á PCRE-vélinni
regmatches(txt, gregexpr("[\\w.]+@[\\w.-]+", txt, perl = TRUE))
[[1]]
[1] "helga@hi.is"

[[2]]
character(0)

[[3]]
[1] "nemandi.1@example.org"
# 2) nota POSIX-klasa sem sjálfgefna vélin skilur
regmatches(txt, gregexpr("[[:alnum:]._]+@[[:alnum:].-]+", txt))
[[1]]
[1] "helga@hi.is"

[[2]]
character(0)

[[3]]
[1] "nemandi.1@example.org"

Sömu föll taka perl = TRUE: grepl(), sub(), gsub(), regexpr().

import re

txt = [
    "Hafðu samband við helga@hi.is",
    "Þetta er ekki netfang",
    "Prófun: nemandi.1@example.org",
]

for lina in txt:
    print(re.findall(r"[\w._%+-]+@[\w.-]+\.[A-Za-z]{2,}", lina))
['helga@hi.is']
[]
['nemandi.1@example.org']

Taktu eftir að í R þarf oft að tvöfalda bakskástrik í strengjum: \\d í R-streng verður \d í regex. Í Python er algengt að nota hráa strengi með r"...", þá þarf síður að tvöfalda bakskástrik.

MikilvægtFyrsta samsvörun eða allar?

Mynstur getur passað víða í sama texta. Föllin skiptast í tvennt: sum skila fyrstu samsvörun frá vinstri, önnur skila öllum.

Fyrsta samsvörun Allar samsvaranir
Base R regexpr() gregexpr()
stringr str_extract() str_extract_all()
Python re.search() re.findall()
pantanir <- "Pantanir: 12, 345 og 6789"

# fyrsta samsvörun
regmatches(pantanir, regexpr("\\d+", pantanir, perl = TRUE))
[1] "12"
# allar samsvaranir
regmatches(pantanir, gregexpr("\\d+", pantanir, perl = TRUE))
[[1]]
[1] "12"   "345"  "6789"
import re

pantanir = "Pantanir: 12, 345 og 6789"

print(re.search(r"\d+", pantanir).group())   # fyrsta samsvörun
12
print(re.findall(r"\d+", pantanir))          # allar samsvaranir
['12', '345', '6789']

Innan hverrar samsvörunar er + gráðugt: það tekur eins marga tölustafi og það kemst upp með í röð, en stoppar á fyrsta stafnum sem passar ekki. Þá er \d+ á 588-5522 ekki allt símanúmerið heldur bara 588 — bandstrikið er ekki tölustafur. Ef númerið allt á að fylgja þarf mynstrið að segja það: \d{3}-\d{4}.

Þetta skiptir máli þegar ein tala á að fara í töflu: fyrsta samsvörun er ekki endilega sú sem þú ætlaðir að lesa. Skoðaðu alltaf allar samsvaranir áður en þú velur eina.

Æfing: tengiliðir

Gefinn er þessi texti:

Jón, jon@example.is, 5551234
Guðrún, gudrun@hi.is, 510-7000
Villa, ekki-netfang, 123
Nemandi, nemandi.1@hi.is, 555 9876
  1. Finndu allar línur sem innihalda netfang.
  2. Finndu öll símanúmer, hvort sem þau eru skrifuð 5551234, 555-1234 eða 555 1234.
  3. Breyttu símanúmerunum yfir í samræmt snið: 555-1234.
  4. Hver af línunum ætti ekki að fara inn í hreina tengiliðatöflu? Af hverju?

Mynstur til að byrja með:

[\w._%+-]+@[\w.-]+\.[A-Za-z]{2,}
\d{3}[- ]?\d{4}

Markmiðið er ekki að skrifa fullkomið regex í fyrstu tilraun. Markmiðið er að geta lesið mynstrið, prófað það, séð hvað það finnur ranglega og lagað það meðvitað.

ÁbendingPrófaðu fyrst utan kóða

Settu textann og mynstrin inn á regex101 áður en þú skrifar lausnina í R eða Python. Skráðu hjá þér eitt dæmi sem passar rétt og eitt dæmi sem mynstrið finnur ekki eða finnur ranglega.