Skip to content

Commit c659d1b

Browse files
authored
Add phone-number exercise (exercism#202)
1 parent bb4388b commit c659d1b

File tree

9 files changed

+344
-0
lines changed

9 files changed

+344
-0
lines changed

config.json

+8
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,14 @@
470470
"prerequisites": [],
471471
"difficulty": 3
472472
},
473+
{
474+
"slug": "phone-number",
475+
"name": "Phone Number",
476+
"uuid": "3737b21b-d732-4b3c-a68f-cdd090b61459",
477+
"practices": [],
478+
"prerequisites": [],
479+
"difficulty": 3
480+
},
473481
{
474482
"slug": "custom-set",
475483
"name": "Custom Set",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Instructions
2+
3+
Clean up user-entered phone numbers so that they can be sent SMS messages.
4+
5+
The **North American Numbering Plan (NANP)** is a telephone numbering system used by many countries in North America like the United States, Canada or Bermuda.
6+
All NANP-countries share the same international country code: `1`.
7+
8+
NANP numbers are ten-digit numbers consisting of a three-digit Numbering Plan Area code, commonly known as _area code_, followed by a seven-digit local number.
9+
The first three digits of the local number represent the _exchange code_, followed by the unique four-digit number which is the _subscriber number_.
10+
11+
The format is usually represented as
12+
13+
```text
14+
NXX NXX-XXXX
15+
```
16+
17+
where `N` is any digit from 2 through 9 and `X` is any digit from 0 through 9.
18+
19+
Sometimes they also have the country code (represented as `1` or `+1`) prefixed.
20+
21+
Your task is to clean up differently formatted telephone numbers by removing punctuation and the country code if present.
22+
23+
For example, the inputs
24+
25+
- `+1 (613)-995-0253`
26+
- `613-995-0253`
27+
- `1 613 995 0253`
28+
- `613.995.0253`
29+
30+
should all produce the output
31+
32+
`6139950253`
33+
34+
**Note:** As this exercise only deals with telephone numbers used in NANP-countries, only 1 is considered a valid country code.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"authors": [
3+
"glennj"
4+
],
5+
"files": {
6+
"solution": [
7+
"phone-number.wren"
8+
],
9+
"test": [
10+
"phone-number.spec.wren"
11+
],
12+
"example": [
13+
".meta/proof.ci.wren"
14+
]
15+
},
16+
"blurb": "Clean up user-entered phone numbers so that they can be sent SMS messages.",
17+
"source": "Exercise by the JumpstartLab team for students at The Turing School of Software and Design.",
18+
"source_url": "https://turing.edu"
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
class PhoneNumber {
2+
static clean(input) {
3+
// remove valid non-digits
4+
var ok = ["+", "(", ")", " ", "-", "."]
5+
var cleaned = ok.reduce(input) {|s, char| s.replace(char, "")}
6+
7+
// check for invalid characters
8+
// anything other than digits and lettes is "punctuation"
9+
var cps = cleaned.codePoints
10+
if (cps.any {|cp| (65 <= cp && cp <= 90) || (97 <= cp && cp <= 122)}) {
11+
Fiber.abort("letters not permitted")
12+
}
13+
if (cps.any {|cp| cp < 48 || cp > 57}) {
14+
Fiber.abort("punctuations not permitted")
15+
}
16+
17+
// validate length
18+
if (cleaned.count < 10) {
19+
Fiber.abort("must not be fewer than 10 digits")
20+
}
21+
if (cleaned.count > 11) {
22+
Fiber.abort("must not be greater than 11 digits")
23+
}
24+
if (cleaned.count == 11) {
25+
if (cleaned[0] != "1") {
26+
Fiber.abort("11 digits must start with 1")
27+
}
28+
cleaned = cleaned[1..-1]
29+
}
30+
31+
// validate area code and exchange code
32+
if (cleaned[0] == "0") {
33+
Fiber.abort("area code cannot start with zero")
34+
}
35+
if (cleaned[0] == "1") {
36+
Fiber.abort("area code cannot start with one")
37+
}
38+
if (cleaned[3] == "0") {
39+
Fiber.abort("exchange code cannot start with zero")
40+
}
41+
if (cleaned[3] == "1") {
42+
Fiber.abort("exchange code cannot start with one")
43+
}
44+
45+
return cleaned
46+
}
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# This is an auto-generated file.
2+
#
3+
# Regenerating this file via `configlet sync` will:
4+
# - Recreate every `description` key/value pair
5+
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
6+
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
7+
# - Preserve any other key/value pair
8+
#
9+
# As user-added comments (using the # character) will be removed when this file
10+
# is regenerated, comments can be added via a `comment` key.
11+
12+
[79666dce-e0f1-46de-95a1-563802913c35]
13+
description = "cleans the number"
14+
15+
[c360451f-549f-43e4-8aba-fdf6cb0bf83f]
16+
description = "cleans numbers with dots"
17+
18+
[08f94c34-9a37-46a2-a123-2a8e9727395d]
19+
description = "cleans numbers with multiple spaces"
20+
21+
[598d8432-0659-4019-a78b-1c6a73691d21]
22+
description = "invalid when 9 digits"
23+
include = false
24+
25+
[2de74156-f646-42b5-8638-0ef1d8b58bc2]
26+
description = "invalid when 9 digits"
27+
reimplements = "598d8432-0659-4019-a78b-1c6a73691d21"
28+
29+
[57061c72-07b5-431f-9766-d97da7c4399d]
30+
description = "invalid when 11 digits does not start with a 1"
31+
32+
[9962cbf3-97bb-4118-ba9b-38ff49c64430]
33+
description = "valid when 11 digits and starting with 1"
34+
35+
[fa724fbf-054c-4d91-95da-f65ab5b6dbca]
36+
description = "valid when 11 digits and starting with 1 even with punctuation"
37+
38+
[c6a5f007-895a-4fc5-90bc-a7e70f9b5cad]
39+
description = "invalid when more than 11 digits"
40+
include = false
41+
42+
[4a1509b7-8953-4eec-981b-c483358ff531]
43+
description = "invalid when more than 11 digits"
44+
reimplements = "c6a5f007-895a-4fc5-90bc-a7e70f9b5cad"
45+
46+
[63f38f37-53f6-4a5f-bd86-e9b404f10a60]
47+
description = "invalid with letters"
48+
include = false
49+
50+
[eb8a1fc0-64e5-46d3-b0c6-33184208e28a]
51+
description = "invalid with letters"
52+
reimplements = "63f38f37-53f6-4a5f-bd86-e9b404f10a60"
53+
54+
[4bd97d90-52fd-45d3-b0db-06ab95b1244e]
55+
description = "invalid with punctuations"
56+
include = false
57+
58+
[065f6363-8394-4759-b080-e6c8c351dd1f]
59+
description = "invalid with punctuations"
60+
reimplements = "4bd97d90-52fd-45d3-b0db-06ab95b1244e"
61+
62+
[d77d07f8-873c-4b17-8978-5f66139bf7d7]
63+
description = "invalid if area code starts with 0"
64+
65+
[c7485cfb-1e7b-4081-8e96-8cdb3b77f15e]
66+
description = "invalid if area code starts with 1"
67+
68+
[4d622293-6976-413d-b8bf-dd8a94d4e2ac]
69+
description = "invalid if exchange code starts with 0"
70+
71+
[4cef57b4-7d8e-43aa-8328-1e1b89001262]
72+
description = "invalid if exchange code starts with 1"
73+
74+
[9925b09c-1a0d-4960-a197-5d163cbe308c]
75+
description = "invalid if area code starts with 0 on valid 11-digit number"
76+
77+
[3f809d37-40f3-44b5-ad90-535838b1a816]
78+
description = "invalid if area code starts with 1 on valid 11-digit number"
79+
80+
[e08e5532-d621-40d4-b0cc-96c159276b65]
81+
description = "invalid if exchange code starts with 0 on valid 11-digit number"
82+
83+
[57b32f3d-696a-455c-8bf1-137b6d171cdf]
84+
description = "invalid if exchange code starts with 1 on valid 11-digit number"
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2024 Exercism
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import "wren-package" for WrenPackage, Dependency
2+
import "os" for Process
3+
4+
class Package is WrenPackage {
5+
construct new() {}
6+
name { "exercism/phone-number" }
7+
dependencies {
8+
return [
9+
Dependency.new("wren-testie", "0.3.0", "https://github.com/joshgoebel/wren-testie.git")
10+
]
11+
}
12+
}
13+
14+
Package.new().default()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import "./phone-number" for PhoneNumber
2+
import "wren-testie/testie" for Testie, Expect
3+
4+
Testie.test("PhoneNumber") { |do, skip|
5+
do.test("cleans the number") {
6+
var actual = PhoneNumber.clean("(223) 456-7890")
7+
var expected = "2234567890"
8+
Expect.value(actual).toEqual(expected)
9+
}
10+
11+
skip.test("cleans numbers with dots") {
12+
var actual = PhoneNumber.clean("223.456.7890")
13+
var expected = "2234567890"
14+
Expect.value(actual).toEqual(expected)
15+
}
16+
17+
skip.test("cleans numbers with multiple spaces") {
18+
var actual = PhoneNumber.clean("223 456 7890 ")
19+
var expected = "2234567890"
20+
Expect.value(actual).toEqual(expected)
21+
}
22+
23+
skip.test("invalid when 9 digits") {
24+
Expect.that {
25+
PhoneNumber.clean("123456789")
26+
}.abortsWith("must not be fewer than 10 digits")
27+
}
28+
29+
skip.test("invalid when 11 digits does not start with a 1") {
30+
Expect.that {
31+
PhoneNumber.clean("22234567890")
32+
}.abortsWith("11 digits must start with 1")
33+
}
34+
35+
skip.test("valid when 11 digits and starting with 1") {
36+
var actual = PhoneNumber.clean("12234567890")
37+
var expected = "2234567890"
38+
Expect.value(actual).toEqual(expected)
39+
}
40+
41+
skip.test("valid when 11 digits and starting with 1 even with punctuation") {
42+
var actual = PhoneNumber.clean("+1 (223) 456-7890")
43+
var expected = "2234567890"
44+
Expect.value(actual).toEqual(expected)
45+
}
46+
47+
skip.test("invalid when more than 11 digits") {
48+
Expect.that {
49+
PhoneNumber.clean("321234567890")
50+
}.abortsWith("must not be greater than 11 digits")
51+
}
52+
53+
skip.test("invalid with letters") {
54+
Expect.that {
55+
PhoneNumber.clean("523-abc-7890")
56+
}.abortsWith("letters not permitted")
57+
}
58+
59+
skip.test("invalid with punctuations") {
60+
Expect.that {
61+
PhoneNumber.clean("523-@:!-7890")
62+
}.abortsWith("punctuations not permitted")
63+
}
64+
65+
skip.test("invalid if area code starts with 0") {
66+
Expect.that {
67+
PhoneNumber.clean("(023) 456-7890")
68+
}.abortsWith("area code cannot start with zero")
69+
}
70+
71+
skip.test("invalid if area code starts with 1") {
72+
Expect.that {
73+
PhoneNumber.clean("(123) 456-7890")
74+
}.abortsWith("area code cannot start with one")
75+
}
76+
77+
skip.test("invalid if exchange code starts with 0") {
78+
Expect.that {
79+
PhoneNumber.clean("(223) 056-7890")
80+
}.abortsWith("exchange code cannot start with zero")
81+
}
82+
83+
skip.test("invalid if exchange code starts with 1") {
84+
Expect.that {
85+
PhoneNumber.clean("(223) 156-7890")
86+
}.abortsWith("exchange code cannot start with one")
87+
}
88+
89+
skip.test("invalid if area code starts with 0 on valid 11-digit number") {
90+
Expect.that {
91+
PhoneNumber.clean("1 (023) 456-7890")
92+
}.abortsWith("area code cannot start with zero")
93+
}
94+
95+
skip.test("invalid if area code starts with 1 on valid 11-digit number") {
96+
Expect.that {
97+
PhoneNumber.clean("1 (123) 456-7890")
98+
}.abortsWith("area code cannot start with one")
99+
}
100+
101+
skip.test("invalid if exchange code starts with 0 on valid 11-digit number") {
102+
Expect.that {
103+
PhoneNumber.clean("1 (223) 056-7890")
104+
}.abortsWith("exchange code cannot start with zero")
105+
}
106+
107+
skip.test("invalid if exchange code starts with 1 on valid 11-digit number") {
108+
Expect.that {
109+
PhoneNumber.clean("1 (223) 156-7890")
110+
}.abortsWith("exchange code cannot start with one")
111+
}
112+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class PhoneNumber {
2+
static clean(input) {
3+
Fiber.abort("Remove this statement and implement this function")
4+
}
5+
}

0 commit comments

Comments
 (0)