Expresii regulate cu deplasare Partea 1

Prezentare generală

Expresele regulate (AKA regex) sunt un limbaj formal care definește o secvență de caractere cu un anumit tipar. În lumea reală, ele pot fi folosite pentru a rezolva o mulțime de probleme cu text semi-structurat. Puteți extrage biții și piesele importante din text cu o mulțime de decorațiuni sau conținut fără legătură. Go are un pachet puternic de regex în biblioteca standard care vă permite să tăiați și săriți text cu regexuri. 

În această serie cu două părți, veți afla ce expresii regulate sunt și cum să utilizați în mod eficient expresii regulate în Go pentru a îndeplini multe sarcini comune. Dacă nu sunteți familiarizați cu expresii regulate, există foarte multe tutoriale. Aici este unul bun.

Înțelegerea expresiilor regulate

Să începem cu un exemplu rapid. Aveți un text și doriți să verificați dacă acesta conține o adresă de e-mail. O adresă de e-mail este specificată riguros în RFC 822. Pe scurt, ea are o parte locală urmată de un simbol @, urmat de un domeniu. Adresa de e-mail va fi separată de restul textului după spațiu. 

Pentru a afla dacă conține o adresă de e-mail, următoarea regex va face: ^ \ W + @ \ w + \. \ W + $. Rețineți că acest regex este puțin permisiv și va permite trimiterea unor adrese de e-mail nevalide. Dar este suficient de bun pentru a demonstra acest concept. Să încercăm pe câteva adrese potențiale de e-mail înainte de a explica cum funcționează:

pachet import principal ("os" "regexp" "fmt") func verificare (eroare err) if err! = nil fmt.Println (err.Error e-mailuri: = [] șir "maro @ fox", "maro @ fox.", "[email protected]", "br @ own @ fox.com" . Pentru a putea comenta pe articolul "fmt.Printf (" √ '% s'), verifica (err) dacă este potrivită fmt.Printf ("√ '% s' un email valid) \ n ", email) altceva fmt.Printf (" X '% s nu este un email valid \ n ", email) Output: X' brown @ fox ' „brun @ vulpe.“ nu este un e-mail valid √ '[email protected]' este un e-mail valid X 'br @ own @ fox.com' nu este un e-mail valid

Expresia noastră regulată funcționează pe această mostră mică. Primele două adrese au fost respinse deoarece domeniul nu avea un punct sau nu avea caractere după punct. Al treilea e-mail a fost formatat corect. Ultimul candidat avea două simboluri @.

Să ne despărțim acest regex: ^ \ W + @ \ w + \. \ W + $

Caracter / Simbol Sens
^ Începutul textului țintă
\ w Orice cuvinte de caractere [0-9A-Za-z_]
+ Cel puțin unul dintre personajele anterioare
@ Literalmente caracterul @ 
\. Caracterul punctual literal. Trebuie scapat cu \
$ Sfârșitul textului țintă

În total, acest regex se va potrivi cu fragmente de text care încep cu unul sau mai multe caractere de cuvânt, urmate de caracterul "@", urmat din nou de unul sau mai multe caractere de cuvânt, urmat de un punct și urmat de încă unul sau mai multe caractere.  

Confruntarea cu caracterele speciale

Următoarele caractere au înțelesuri speciale în expresiile regulate: .+? * () | [] ^ $ \. Am văzut deja mulți dintre ei în exemplul de e-mail. Dacă vrem să le potrivim literalmente, trebuie să le scăpăm cu o lovitură inversă. Să introducem o funcție de ajutor Meci() care ne va salva o mulțime de tastare. Este nevoie de un model și de un text, utilizează regexp.Match () pentru a potrivi modelul cu textul (după conversia textului într-o matrice de octeți) și tipărește rezultatele:

funcția (șir de șablon, șir de text) matched, _: = regexp.Match (model, [] octet (text)), dacă este potrivită fmt.Println (" fmt.Println ("X", model, ":", text)

Iată un exemplu de potrivire a unui personaj obișnuit, cum ar fi z comparativ cu un personaj special cum ar fi ?:

func principală () text: = "Pot să fiu chezburger?" model: = "z" potrivire (model, text) model = "\\?" potrivire (model, text) model = '\?' potrivire (model, text) Ieșire: √ z: Pot haz cheezburger? √ \? : Pot să văd ce faci? √ \? : Pot să haz cheezburger? 

Modelul regex \? conține un backslash care trebuie să fie scos cu o altă spate, atunci când este reprezentat ca un șir regulat Go. Motivul este că și coloana vertebrală este folosită și pentru a scăpa de caracterele speciale din șirurile Go, cum ar fi noua linie (\ n). Dacă doriți să potriviți caracterul invers în sine, veți avea nevoie de patru tăieturi! 

Soluția este să folosiți șiruri de caractere goale cu spătarul (') în loc de ghilimele duble. Desigur, dacă doriți să potriviți caracterul de linie nouă, trebuie să vă întoarceți la șiruri de caractere regulate și să faceți față mai multor evadări din spate.

Reprezentări și repetiții

În cele mai multe cazuri, nu încercați să potriviți literalmente o secvență de caractere specifice, cum ar fi "abc", ci o secvență de lungime necunoscută, poate cu unele caractere cunoscute injectate undeva. Regexes sprijină acest caz de utilizare cu punctul  . caracterul caracteristic care reprezintă orice caracter. * caracterul special repetă caracterul anterior (sau grupul) zero sau de mai multe ori. Dacă le combinați, ca și în .*, atunci potriviți ceva deoarece înseamnă pur și simplu zero sau mai multe caractere. + este foarte asemănătoare cu *, dar se potrivește cu unul sau mai multe dintre caracterele sau grupurile anterioare. Asa de .+ se va potrivi cu orice text ne-gol.

Utilizarea limitelor

Există trei tipuri de limite: începutul textului marcat de ^, sfârșitul textului marcat de $, și limita de cuvânt indicată de \ b. De exemplu, luați în considerare acest text din filmul clasic Prințesa mireasă: "Numele meu este Inigo Montoya. Mi-ai ucis tatăl, pregătește-mă să mor." Dacă potriviți doar "tatăl", obțineți un meci, dar dacă căutați "tată" la sfârșitul textului, trebuie să adăugați $ caracter, și apoi nu va fi nici o potrivire. Pe de altă parte, potrivirea "Bună ziua" la început funcționează bine.

func main () text: = "Bună ziua, numele meu este Inigo Montoya, mi-ai ucis tatăl, pregătește-mă să mor." model: = meci "tată" (model, text) model = "tată $ $" meci (model, text) model = "^ Bună ziua" mi-ai ucis tatăl, pregăteam să mor. X tatăl: Bună, numele meu este Inigo Montoya, l-ai omorât pe tata, pregătindu-mă să mor. Bună ziua, numele meu este Inigo Montoya, mi-ai ucis tatăl, pregătește-mă să mor. 

Limitele cuvintelor privesc fiecare cuvânt. Puteți începe și / sau încheia un model cu \ b. Rețineți că semnele de punctuație, precum virgulele, sunt considerate limite și nu parte a cuvântului. Iată câteva exemple:

func main () text: = 'Bună ziua, numele meu este Inigo Montoya, mi-ai ucis tatăl, pregătește-mă să mor. model: = 'ucide' meci (model, text) pattern = '\ bkill \ b' meci (model, text) ) pattern = '\ bkilled \ b' potrivire (model, text) model = '\ bMontoya, \ b' potrivire (model, text) Ieșire: √ ucide: Bună, numele meu este Inigo Montoya a muri. √ bkill: Bună ziua, numele meu este Inigo Montoya, l-ai omorât pe tatăl meu, pregătindu-se să moară. X kill \ b: Bună, numele meu este Inigo Montoya, l-ai omorât pe tatăl meu, pregătit să moară. X \ bkill \ b: Bună ziua, numele meu este Inigo Montoya, mi-ai ucis tatăl, mă pregătesc să mor. √ \ bkilled \ b: Bună ziua, numele meu este Inigo Montoya, mi-ai ucis tatăl, mă pregătesc să mor. X \ bMontoya, \ b: Bună, numele meu este Inigo Montoya, mi-ai ucis tatăl, te pregătești să mori.

Utilizarea claselor

Este adesea util să tratați toate grupurile de caractere împreună ca toate cifrele, caracterele spațiului alb sau toate caracterele alfanumerice. Golang susține clasele POSIX, care sunt:

Clasa de caractere Sens
[: Alnum:]
alfanumeric (≡ [0-9A-Za-z])
[:alfa:]
alfabetic (≡ [A-Za-z])
[: Ascii:] 
ASCII (≡ [\ x00- \ x7F])
[:gol:] 
martor (≡ [\ t])
[: Cntrl:]
controlul (≡ [\ x00- \ x1F \ x7F])
[:cifră:]
cifre (≡ [0-9])
[:grafic:]
grafică (≡ [! - ~] == [A-Za-z0-9! "# $% & '() * +, \ -.<=>?@ [\\\] ^ _ '| ~])
[:inferior:] 
caractere mici (≡ [a-z])
[:imprimare:] 
printabil (≡ [- ~] == [[: graf:]])
[: Punct:]
punctuația (≡ [! - /: - @ [- '- ~])
[:spaţiu:]
spațiu alb (≡ [\ t \ n \ v \ f \ r])
[:superior:]
caseta superioară (≡ [A-Z])
[:cuvânt:]
cuvinte de caractere (≡ [0-9A-Za-z_])
[: Xdigit:]
cifră hexagonală (≡ [0-9A-Fa-f])

În exemplul următor, voi folosi [:cifră:] pentru a căuta numere în text. De asemenea, am aratat aici cum sa cautati un numar exact de caractere prin adaugarea numarului dorit in bretele curlate.

func main () text: = 'Răspunsul la viață, univers și totul este 42'. model: = "[[: digit:]] 3 ]] 2 "(model, text) Ieșire: X [[: cifră:]] 3: Răspunsul la viață, univers și totul este 42. √ [ Răspunsul la viață, univers și totul este 42. 

Puteți defini propriile clase prin introducerea caracterelor în paranteze pătrate. De exemplu, dacă doriți să verificați dacă un text este o secvență ADN validă care conține numai caracterele ACGT apoi utilizați ^ [ACGT] * $ regex:

functie principala () text: = "AGGCGTTGGGAACGTT" model: = "^ [ACGT] * $ $ potrivire (model, text) text = ] * $: AGGCGTTGGGAACGTT X ^ [ACGT] * $: nu este exact o secvență ADN

Utilizarea alternativelor

În unele cazuri, există mai multe alternative viabile. Potrivirea URL-urilor HTTP poate fi caracterizată printr-o schemă de protocol, care este fie http: // sau https: //. Caracterul conductei | vă permite să alegeți între alternative. Aici este un regex care le va sorta: (Http) | (https):. // \ w + \ \ w 2. Se traduce într-un șir care începe cu http: // sau https: // urmat de cel puțin un caracter de cuvânt urmat de un punct urmat de cel puțin două caractere de cuvânt.

funcția principală () pattern: = '(http) | (https): // \ w + \. \ w 2, potrivire (model, "http://tutsplus.com" : //tutsplus.com ") (model," htt: //tutsplus.com ") Ieșire: √ (http) | (https): // \ w + /tutsplus.com √ (http) | (https): // \ w + \. \ w 2,: https://tutsplus.com X (http) 2,: htt: //tutsplus.com

Concluzie

În această parte a tutorialului, am acoperit o mulțime de terenuri și am învățat multe despre expresiile regulate, cu exemple practice folosind biblioteca regexp Golang. Ne-am concentrat pe potrivirea pură și pe modul în care ne exprimăm intențiile folosind expresii regulate. 

În partea a doua, ne vom concentra pe folosirea expresiilor regulate pentru a lucra cu textul, inclusiv găsirea fuzzy, înlocuirea, gruparea și tratarea liniilor noi.

Cod