Треки
/
Factor
Factor
/
Вправи
/
Реєстровий вартовий
Реєстровий вартовий

Реєстровий вартовий

Навчальна вправа

Вступ

Ми вже знаємо основи: класи символів, як-от \d і [A-Z], квантифікатори, як-от {4} і +, а також слова matches?, all-matching-subseqs і re-replace. Ця вправа додає ті частини регулярних виразів, які описують структуру та контекст. Вони живуть у тому самому словнику regexp, записані тим самим літералом R/ /.

Межі

Межі збігаються з позицією, а не із символом:

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

Оскільки $ означає кінець рядка тексту (англ. string), для буквального знака долара пишіть \$.

Межа слова (\b) - це місце, де символ слова зустрічається з тим, що не є символом слова. Символами слова є літери, цифри та підкреслення; усе інше, а саме пробіли, розділові знаки та обидва кінці рядка тексту, вважається межею. Тож \bcat\b збігається з cat лише тоді, коли воно стоїть саме по собі:

USING: regexp ;

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

Групування та альтернація

Круглі дужки ( ) групують частину шаблону так, що квантифікатор (або |, тобто «це або те») застосовується до всієї групи:

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)

Останній шаблон читається так: «знак долара, одна або більше цифр, а потім необовʼязкова група з крапки та двох цифр».

Зауваження: у Factor група лише структурує шаблон. На відміну від деяких інструментів для регулярних виразів, витягнути назад текст, із яким збіглася група, не вийде: видобування захоплених груп тут немає, а зворотні посилання, як-от \1, не підтримуються. Щоб вибрати текст навколо орієнтира, скористаймося натомість перевіркою оточення (див. нижче).

Перевірка оточення: збіг за контекстом, без його споживання

Перевірка оточення зʼясовує, що стоїть безпосередньо перед поточним місцем або одразу після нього, не роблячи ці символи частиною збігу. Вона має «нульову ширину»: те, що вона перевіряє, не входить до результату.

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

Перевірка оточення вибіркова: ті самі символи збігаються чи ні залежно від того, що стоїть поруч. Звичайний \d+ хапає кожне число; перевірка назад і перевірка вперед залишають лише ті, у яких правильний сусід:

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)

Опції

Додайте літеру після закривальної /, щоб змінити поведінку всього шаблону. i робить його незалежним від регістру:

USING: regexp ;

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

Перетворення кожного збігу

all-matching-subseqs віддає нам текст збігу. map-matches іде на крок далі: він запускає quotation для кожного збігу й збирає результати. Quotation отримує індекс start збігу, його індекс end і весь рядок тексту; subseq перетворює ці три на текст збігу, який ми потім перетворюємо:

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)

Його родич, призначений лише для побічних ефектів, each-match, запускає quotation для кожного збігу, нічого не збираючи.

Вказівки

Ми ведемо бухгалтерію невеликої компанії, і щодня транзакції надходять неохайними рядками тексту. Ми будемо використовувати регулярні вирази, щоб перевіряти правильність сум, витягувати числа за символом, який їх позначає, і позначати рядки, які потребують пильнішої уваги.

1. Перевірте правильність суми

Правильно оформлена сума складається з символу $, однієї або більше цифр та необовʼязкової частини центів: крапки й рівно двох цифр після неї. Наприклад, $100 або $100.50, але не $100.5. Визначте valid-amount?, яка повертає t, коли весь рядок тексту (англ. string) є правильно оформленою сумою.

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

2. Витягніть доларові суми

Визначте dollar-amounts, яка повертає кожне число, що стоїть безпосередньо після $ у рядку — лише цифри, без $ — у тому ж порядку.

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

3. Витягніть відсотки

Визначте percentages, яка повертає кожне число, за яким безпосередньо стоїть %.

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

4. Позначте рядок

Визначте flagged?, яка повертає t, коли рядок згадує refund або chargeback у будь-якому поєднанні великих і малих літер.

"Issued a REFUND today" flagged? .   ! => t
"a normal sale"         flagged? .   ! => f
Редагувати через GitHub Посилання відкривається в новому вікні або вкладці
Factor Exercism

Час розпочати Реєстровий вартовий?

Зареєструйтеся на Exercism, щоб вивчати й опановувати Factor, а також 47 концепцій163 вправи та справжнє наставництво від людей, і все це безкоштовно.