Track
/
Factor
Factor
/
Esercizi
/
Vedetta sul registro
Vedetta sul registro

Vedetta sul registro

Esercizio di apprendimento

Introduzione

Conosci già le basi: classi di caratteri come \d e [A-Z], quantificatori come {4} e +, e le parole matches?, all-matching-subseqs e re-replace. Questo esercizio aggiungerà le parti delle espressioni regolari che descrivono struttura e contesto. Vivono nello stesso vocabolario regexp, scritto con lo stesso letterale R/ /.

Ancore

Le ancore corrispondono a una posizione invece che a un carattere:

^    ! the start of the string
$    ! the end of the string
\b   ! a word boundary

Dato che $ indica la fine della stringa, scrivi \$ quando vuoi indicare un simbolo del dollaro letterale.

Un confine di parola (\b) è il punto in cui un carattere di parola incontra un carattere che non lo è. I caratteri di parola sono lettere, cifre e il trattino basso; tutto il resto (spazi, punteggiatura e le due estremità della stringa) conta come confine. Quindi \bcat\b corrisponde a cat solo quando è da solo:

USING: regexp ;

"cat nap" R/ \bcat\b/ re-contains? .   ! => t
"scatter" R/ \bcat\b/ re-contains? .   ! => f   (cat sits inside a word)

Raggruppamento e alternanza

Le parentesi tonde ( ) raggruppano parte di un pattern, così che un quantificatore, o una | (che significa «questo o quello»), si applichi all'intero gruppo:

USING: regexp ;

"abab" R/ (ab)+/ matches? .                ! => t   (+ applies to "ab")
"dog"  R/ cat|dog/ matches? .              ! => t   (either word)
"$100.50" R/ \$\d+(\.\d{2})?/ matches? .   ! => t
"$100"    R/ \$\d+(\.\d{2})?/ matches? .   ! => t   (the group is optional)

L'ultimo pattern si legge così: «un simbolo del dollaro, una o più cifre, poi un gruppo opzionale formato da un punto e due cifre».

Nota: in Factor un gruppo si limita a strutturare il pattern. A differenza di alcuni strumenti per le espressioni regolari, non puoi recuperare il testo con cui il gruppo ha corrisposto: non esiste l'estrazione dei gruppi di cattura, e i backreference come \1 non sono supportati. Per estrarre il testo attorno a un punto di riferimento, usa invece il lookaround (più avanti).

Lookaround: corrispondere in base al contesto, senza consumarlo

Un lookaround controlla cosa viene subito prima o subito dopo il punto corrente senza rendere quei caratteri parte della corrispondenza. È a «larghezza zero»: ciò che verifica non è incluso nel risultato.

(?=...)    ! lookahead:           ... must follow
(?!...)    ! negative lookahead:  ... must NOT follow
(?<=...)   ! lookbehind:          ... must come before
(?<!...)   ! negative lookbehind: ... must NOT come before

Il lookaround è selettivo: gli stessi caratteri corrispondono o no a seconda di cosa hanno accanto. Un semplice \d+ prende tutti i numeri; il lookbehind e il lookahead tengono solo quelli con il vicino giusto:

USING: regexp ;

"3 for $10 or 10 for $30" R/ \d+/ all-matching-subseqs .
! => { "3" "10" "10" "30" }   (every number)

"3 for $10 or 10 for $30" R/ (?<=\$)\d+/ all-matching-subseqs .
! => { "10" "30" }            (only the prices — the bare 3 and 10 drop)

"buy 2 at 15% off, 4 at 30% off" R/ \d+(?=%)/ all-matching-subseqs .
! => { "15" "30" }            (only the discounts — the bare 2 and 4 drop)

Opzioni

Aggiungi una lettera dopo la / di chiusura per cambiare il comportamento dell'intero pattern. La i lo rende insensibile alle maiuscole e alle minuscole:

USING: regexp ;

"REFUND"  R/ refund/i matches? .       ! => t
"Refund"  R/ refund/i matches? .       ! => t

Trasformare ogni corrispondenza

all-matching-subseqs ti dà il testo corrispondente. map-matches fa un passo in più: esegue una quotation su ogni corrispondenza e raccoglie i risultati. La quotation riceve l'indice start della corrispondenza, il suo indice end e l'intera stringa; subseq trasforma quei tre elementi nel testo corrispondente, che poi puoi trasformare:

map-matches ( string regexp quot: ( start end string -- obj ) -- seq )
USING: math regexp sequences ;

"a1 b22 c333" R/ \d+/ [ subseq length ] map-matches .
! => { 1 2 3 }     (the length of each run of digits)

Il suo cugino che si limita agli effetti collaterali, each-match, esegue una quotation su ogni corrispondenza senza raccogliere nulla.

Istruzioni

Tieni la contabilità di una piccola azienda, ed ogni giorno le transazioni arrivano sotto forma di righe di testo disordinate. Userai le espressioni regolari per convalidare gli importi, estrarre le cifre in base al simbolo che le contrassegna e segnalare le righe che meritano un'occhiata più attenta.

1. Verifica un importo

Un importo ben formato è composto da un $, una o più cifre e una parte in centesimi facoltativa formata da un punto seguito da esattamente due cifre: $100 o $100.50, ma non $100.5. Definisci valid-amount?, che restituisce t quando l'intera stringa è un importo ben formato.

"$100.50" valid-amount? .   ! => t
"$100"    valid-amount? .   ! => t
"$100.5"  valid-amount? .   ! => f

2. Estrai le cifre in dollari

Definisci dollar-amounts, che restituisce, in ordine, ogni numero che segue direttamente un $ nella riga: le sole cifre, senza il $.

"spent $100 and $25 today" dollar-amounts .
! => { "100" "25" }

3. Estrai le percentuali

Definisci percentages, che restituisce ogni numero seguito immediatamente da un %.

"up 5% then down 12%" percentages .
! => { "5" "12" }

4. Segnala una riga

Definisci flagged?, che restituisce t quando la riga menziona refund o chargeback, in qualsiasi combinazione di maiuscole e minuscole.

"Issued a REFUND today" flagged? .   ! => t
"a normal sale"         flagged? .   ! => f
Modifica tramite GitHub Il link si apre in una nuova finestra o scheda
Factor Exercism

Vuoi iniziare Vedetta sul registro?

Iscriviti a Exercism per imparare e padroneggiare Factor con 47 concetti163 esercizi e il mentoring di persone reali, tutto gratis.