Skip to content

Implemented all "Phone Number" problems from the canonical test data. (#465) #472

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
7 changes: 1 addition & 6 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -293,12 +293,7 @@
"uuid": "c211045e-da97-479d-9df4-5d812573e2d0",
"practices": [],
"prerequisites": [],
"difficulty": 2,
"topics": [
"interfaces",
"parsing",
"strings"
]
"difficulty": 2
},
{
"slug": "queen-attack",
Expand Down
3 changes: 2 additions & 1 deletion exercises/practice/phone-number/.meta/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"cpaulbond"
],
"contributors": [
"yurrriq"
"yurrriq",
"borderite"
],
"files": {
"solution": [
Expand Down
91 changes: 75 additions & 16 deletions exercises/practice/phone-number/.meta/example.el
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions exercises/practice/phone-number/.meta/tests.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"

62 changes: 43 additions & 19 deletions exercises/practice/phone-number/phone-number-test.el
Original file line number Diff line number Diff line change
@@ -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:

Expand All @@ -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")))
Expand All @@ -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

2 changes: 1 addition & 1 deletion exercises/practice/phone-number/phone-number.el
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
;;; phone-number.el --- phone-number Exercise (exercism) -*- lexical-binding: t; -*-
;;; phone-number.el --- phone-number (exercism) -*- lexical-binding: t; -*-

;;; Commentary:

Expand Down