Racket: Сравнение строк и символов, предикаты
Сравнение строк и строковых символов
Пусть заголовок вас не смущает: сравнить 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!
Racket: Сравнение строк и символов, предикаты
Сравнение строк и строковых символов
Пусть заголовок вас не смущает: сравнить 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!
Ваше упражнение проверяется по этим тестам
#lang racket
(require (only-in rackunit check-true check-false test-begin))
(require "index.rkt")
(test-begin
(check-false (password-valid? ""))
(check-false (password-valid? "***"))
(check-false (password-valid? "a b"))
(check-false (password-valid? "a1?"))
(check-true (password-valid? "god"))
(check-true (password-valid? "LOVE"))
(check-true (password-valid? "123456"))
(check-true (password-valid? "U2")))
(test-begin
(check-false (password-good? ""))
(check-false (password-good? "***"))
(check-false (password-good? "a b"))
(check-false (password-good? "a1?"))
(check-false (password-good? "god"))
(check-false (password-good? "LOVE"))
(check-false (password-good? "123456"))
(check-false (password-good? "U2"))
(check-false (password-good? "9876543210"))
(check-false (password-good? "Antananarivo"))
(check-true (password-good? "1cat1dog"))
(check-true (password-good? "R2D2andC3PO")))Решение учителя откроется через:
20:00
