Пусть заголовок вас не смущает: сравнить char
и string
не получится, ведь это разные типы!
Но и пару строк или пару строковых символов сравнить с помощью функций "=
" и "<"
не получится: в Racket эти функции работают только с числами. Чтобы соотносить между собой значения string
и char
в коде на Racket, вам нужно использовать функции с именами вида string=?
и char<?
или, проще говоря, "тип"+"оператор"+"?". И запомнить, и использовать эти функции довольно просто:
(char<? #\a #\b) ; #t
(char>? #\c #\b #\a) ; #t
(char=? #\a #\b) ; #f
(string<? "a" "b") ; #t
(string>? "c" "b" "a") ; #t
(string=? "a" "b") ; #f
Глядя на этот пример, вы и сами сможете догадаться, как работают функции string<=?
и char>=?
:)
Упомянутые функции сравнивают строки и строковые символы буквально или, как говорят, лексикографически. Однако при работе с текстом часто нужно сопоставлять строки без учёта регистра, или производить регистронезависимое сравнение (case-insensitive comparison). В Racket для каждой функции сравнения есть регистронезависимый вариант, имеющий суффикс -ci
("case-insensitive"):
(string=? "Apple" "apple") ; #f
(string-ci=? "Apple" "apple") ; #t
(char>? #\C #\b) ; #f
(char-ci>? #\C #\b) ; #t
Строковые символы могут быть буквами, цифрами, знаками препинания. Более того, буквы могут принадлежать разным алфавитам, одни из которых имеют разные регистры, к другим же данная концепция в принципе не применима. Получается, что некоторый строковый символ может принадлежать к одной или сразу к нескольким группам символов. Проверить принадлежность к основным группам символов можно с помощью набора предикатов с именами вида char-alphabetic?
и char-lower-case?
:
(char-alphabetic? #\a) ; #t
(char-alphabetic? #\u3BB) ; #t — "λ" это буква, пусть и греческая
(char-lower-case? #\a) ; #t
(char-lower-case? #\A) ; #f
Предикатов такого вида в Racket больше десятка, почитать обо всех вы сможете в документации.
Отдельных функций, которые бы проверяли, что все символы некоторой строки принадлежат к некоторой группе, Racket не предоставляет. Впрочем, организовать такую проверку довольно просто, если взять функцию andmap
, работающую со списками, и объединить со string->list
:
(andmap char-alphabetic? (string->list "asd")) ; #t
(andmap char-alphabetic? (string->list "r2d2")) ; #f
Если заменить andmap
на ormap
, то вместо проверки на "все символы…" получится проверка на "хотя бы один символ…"!
Реализуйте два предиката: password-valid?
и password-good?
. Оба должны оценивать строку.
password-valid?
должен возвращать #t
, если строка состоит только из букв и цифр (char-alphabetic?
и char-numeric?
) и при этом имеет ненулевую длину.
password-good?
должен возвращать #t
, если строка содержит и буквы, и цифры, а длина строки не меньше восьми символов. И, разумеется, хороший пароль должен быть valid!
Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.
В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.
Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.
Ваше упражнение проверяется по этим тестам
1#lang racket
2
3(require (only-in rackunit check-true check-false test-begin))
4(require "index.rkt")
5
6(test-begin
7 (check-false (password-valid? ""))
8 (check-false (password-valid? "***"))
9 (check-false (password-valid? "a b"))
10 (check-false (password-valid? "a1?"))
11
12 (check-true (password-valid? "god"))
13 (check-true (password-valid? "LOVE"))
14 (check-true (password-valid? "123456"))
15 (check-true (password-valid? "U2")))
16
17(test-begin
18 (check-false (password-good? ""))
19 (check-false (password-good? "***"))
20 (check-false (password-good? "a b"))
21 (check-false (password-good? "a1?"))
22
23 (check-false (password-good? "god"))
24 (check-false (password-good? "LOVE"))
25 (check-false (password-good? "123456"))
26 (check-false (password-good? "U2"))
27
28 (check-false (password-good? "9876543210"))
29 (check-false (password-good? "Antananarivo"))
30
31 (check-true (password-good? "1cat1dog"))
32 (check-true (password-good? "R2D2andC3PO")))
33
Решение учителя откроется через: