diff --git a/config.json b/config.json index a9e8694f..8fc2bb5d 100644 --- a/config.json +++ b/config.json @@ -293,12 +293,7 @@ "uuid": "c211045e-da97-479d-9df4-5d812573e2d0", "practices": [], "prerequisites": [], - "difficulty": 2, - "topics": [ - "interfaces", - "parsing", - "strings" - ] + "difficulty": 2 }, { "slug": "queen-attack", diff --git a/exercises/practice/phone-number/.meta/config.json b/exercises/practice/phone-number/.meta/config.json index c475338c..60881337 100644 --- a/exercises/practice/phone-number/.meta/config.json +++ b/exercises/practice/phone-number/.meta/config.json @@ -3,7 +3,8 @@ "cpaulbond" ], "contributors": [ - "yurrriq" + "yurrriq", + "borderite" ], "files": { "solution": [ diff --git a/exercises/practice/phone-number/.meta/example.el b/exercises/practice/phone-number/.meta/example.el index 03316fa2..79bf0bcf 100644 --- a/exercises/practice/phone-number/.meta/example.el +++ b/exercises/practice/phone-number/.meta/example.el @@ -2,32 +2,91 @@ ;;; Commentary: -;;; Code: +(define-error 'short-phone-num-error "must not be fewer than 10 digits") +(define-error 'long-phone-num-error "must not be greater than 11 digits") +(define-error 'letters-in-phone-num-error "letters not permitted") +(define-error 'punctuations-in-phone-num-error "punctuations not permitted") +(define-error 'country-code-error "country code must be 1") +(define-error 'area-code-starting-with-0-error "area code cannot start with zero") +(define-error 'area-code-starting-with-1-error "area code cannot start with one") +(define-error 'exchange-code-starting-with-0-error "exchange code cannot start with zero") +(define-error 'exchange-code-starting-with-1-error "exchange code cannot start with one") +(defun char-digit-p (x) + (<= ?0 x ?9)) -(defun numbers (num) - (let ((number (replace-regexp-in-string "[^0-9]+" "" num))) - (cond - ((= (length number) 10) number) - ((and (= (length number) 11) - (string-equal (substring number 0 1) "1")) (substring number 1)) - (t "0000000000")))) +(defun char-lowercase-p (x) + (<= ?a x ?z)) +(defun char-uppercase-p (x) + (<= ?A x ?Z)) -(defun area-code (num) - (substring (numbers num) 0 3)) - +(defun char-alphabetic-p (x) + (or (char-lowercase-p x) + (char-uppercase-p x))) -(defun prefix (num) - (substring (numbers num) 3 6)) +(defun char-punctuation-p (x) + (or (<= 33 x 39) + (= x 42) + (= x 44) + (= x 47) + (<= 58 x 64) + (<= 91 x 96) + (<= 123 x 126))) +(defun negate (pred) + (lambda (&rest args) (apply pred args))) -(defun line-number (num) - (substring (numbers num) 6)) +(defun string-remove (s pred) + (let* ((n (length s)) + (to-str (make-string n ?\0)) + (k 0)) + (dotimes (i n) + (let ((x (aref s i))) + (when (funcall pred x) + (setf (aref to-str k) x) + (cl-incf k)))) + (substring to-str 0 k))) +(defun numbers (num) + "Converts a num string into a string of digits." + (cond + ((cl-find-if #'char-alphabetic-p num) + (signal 'letters-in-phone-num-error num)) + ((cl-find-if #'char-punctuation-p num) + (signal 'punctuations-in-phone-num-error num))) + (let* ((digits (string-remove num (negate #'char-digit-p))) + (n (length digits))) + (cond + ((< n 10) (signal 'short-phone-num-error num)) + ((> n 11) (signal 'long-phone-num-error num))) + (if (= n 11) + (if (= (aref digits 0) ?1) + (setf digits (substring digits 1)) + (signal 'country-code-error num))) + (let ((y (aref digits 0))) + (cond + ((= y ?0) + (signal 'area-code-starting-with-0-error num)) + ((= y ?1) + (signal 'area-code-starting-with-1-error num))) + (let ((y (aref digits 3))) + (cond + ((= y ?0) + (signal 'exchange-code-starting-with-0-error num)) + ((= y ?1) + (signal 'exchange-code-starting-with-1-error num))))) + digits)) + +(defun area-code (num) + (let ((digits (numbers num))) + (substring digits 0 3))) (defun pprint (num) - (format "(%s) %s-%s" (area-code num) (prefix num) (line-number num))) + (let ((digits (numbers num))) + (format "(%s) %s-%s" (substring digits 0 3) + (substring digits 3 6) + (substring digits 6 10)))) (provide 'phone-number) diff --git a/exercises/practice/phone-number/.meta/tests.toml b/exercises/practice/phone-number/.meta/tests.toml index 24dbf07a..4fe47d59 100644 --- a/exercises/practice/phone-number/.meta/tests.toml +++ b/exercises/practice/phone-number/.meta/tests.toml @@ -82,3 +82,4 @@ description = "invalid if exchange code starts with 0 on valid 11-digit number" [57b32f3d-696a-455c-8bf1-137b6d171cdf] description = "invalid if exchange code starts with 1 on valid 11-digit number" + diff --git a/exercises/practice/phone-number/phone-number-test.el b/exercises/practice/phone-number/phone-number-test.el index 36a73088..b1e66134 100644 --- a/exercises/practice/phone-number/phone-number-test.el +++ b/exercises/practice/phone-number/phone-number-test.el @@ -1,4 +1,4 @@ -;;; phone-number-test.el --- Tests for phone-number (exercism) -*- lexical-binding: t; -*- +;;; phone-number-test.el --- Phone Number (exercism) -*- lexical-binding: t; -*- ;;; Commentary: @@ -9,35 +9,59 @@ (declare-function area-code "phone-number.el" (num)) (declare-function pprint "phone-number.el" (num)) -(ert-deftest cleans-number-test () - (should (equal (numbers "(223) 456-7890") "2234567890"))) +(ert-deftest cleans-the-number () + (should (string= (numbers "(223) 456-7890") "2234567890"))) +(ert-deftest cleans-numbers-with-dots () + (should (string= (numbers "223.456.7890") "2234567890"))) -(ert-deftest cleans-numbers-with-dots-test () - (should (equal (numbers "223.456.7890") "2234567890"))) +(ert-deftest cleans-numbers-with-multiple-spaces () + (should (string= (numbers "223 456 7890 ") "2234567890"))) +(ert-deftest invalid-when-9-digits () + (should-error (numbers "123456789") :type 'short-phone-num-error)) -(ert-deftest valid-when-11-digits-and-first-is-1-test () - (should (equal (numbers "12234567890") "2234567890"))) +(ert-deftest invalid-when-11-digits-does-not-start-with-a-1 () + (should-error (numbers "22234567890") :type 'country-code-error)) +(ert-deftest valid-when-11-digits-and-starting-with-1 () + (should (string= (numbers "12234567890") "2234567890"))) -(ert-deftest invalid-when-11-digits-test () - (should (equal (numbers "21234567890") "0000000000"))) +(ert-deftest valid-when-11-digits-and-starting-with-1-even-with-punctuation () + (should (string= (numbers "+1 (223) 456-7890") "2234567890"))) +(ert-deftest invalid-when-more-than-11-digits () + (should-error (numbers "321234567890") :type 'long-phone-num-error)) -(ert-deftest invalid-when-9-digits-test () - (should (equal (numbers "123456789") "0000000000"))) +(ert-deftest invalid-with-letters () + (should-error (numbers "523-abc-7890") :type 'letters-in-phone-num-error)) -(ert-deftest invalid-when-more-than-11-digits-test () - (should (equal (numbers "321234567890") "0000000000"))) +(ert-deftest invalid-with-punctuations () + (should-error (numbers "523-@:!-7890") :type 'punctuations-in-phone-num-error)) -(ert-deftest invalid-with-letters () - (should (equal (numbers "523-abc-7890") "0000000000"))) +(ert-deftest invalid-if-area-code-starts-with-0 () + (should-error (numbers "(023) 456-7890") :type 'area-code-starting-with-0-error)) +(ert-deftest invalid-if-area-code-starts-with-1 () + (should-error (numbers "(123) 456-7890") :type 'area-code-starting-with-1-error)) -(ert-deftest invalid-with-punctuations () - (should (equal (numbers "523-@:!-7890") "0000000000"))) +(ert-deftest invalid-if-exchange-code-starts-with-0 () + (should-error (numbers "(223) 056-7890") :type 'exchange-code-starting-with-0-error)) + +(ert-deftest invalid-if-exchange-code-starts-with-1 () + (should-error (numbers "(223) 156-7890") :type 'exchange-code-starting-with-1-error)) +(ert-deftest invalid-if-area-code-starts-with-0-on-valid-11-digit-number () + (should-error (numbers "1 (023) 456-7890") :type 'area-code-starting-with-0-error)) + +(ert-deftest invalid-if-area-code-starts-with-1-on-valid-11-digit-number () + (should-error (numbers "1 (123) 456-7890") :type 'area-code-starting-with-1-error)) + +(ert-deftest invalid-if-exchange-code-starts-with-0-on-valid-11-digit-number () + (should-error (numbers "1 (223) 056-7890") :type 'exchange-code-starting-with-0-error)) + +(ert-deftest invalid-if-exchange-code-starts-with-1-on-valid-11-digit-number () + (should-error (numbers "1 (223) 156-7890") :type 'exchange-code-starting-with-1-error)) (ert-deftest area-code-test () (should (equal (area-code "2234567890") "223"))) @@ -50,6 +74,6 @@ (ert-deftest pprint-full-us-phone-number-test () (should (equal (pprint "12234567890") "(223) 456-7890"))) - -(provide 'phone-number) +(provide 'phone-number-test) ;;; phone-number-test.el ends here + diff --git a/exercises/practice/phone-number/phone-number.el b/exercises/practice/phone-number/phone-number.el index 61cac595..a08eee0c 100644 --- a/exercises/practice/phone-number/phone-number.el +++ b/exercises/practice/phone-number/phone-number.el @@ -1,4 +1,4 @@ -;;; phone-number.el --- phone-number Exercise (exercism) -*- lexical-binding: t; -*- +;;; phone-number.el --- phone-number (exercism) -*- lexical-binding: t; -*- ;;; Commentary: