Skip to content

Commit

Permalink
Add phone-number exercise
Browse files Browse the repository at this point in the history
  • Loading branch information
ageron committed Oct 9, 2024
1 parent 9f2502e commit e5cd967
Show file tree
Hide file tree
Showing 8 changed files with 305 additions and 0 deletions.
8 changes: 8 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,14 @@
"prerequisites": [],
"difficulty": 3
},
{
"slug": "phone-number",
"name": "Phone Number",
"uuid": "8ccc518a-562e-49a3-8690-affe98a091b5",
"practices": [],
"prerequisites": [],
"difficulty": 3
},
{
"slug": "protein-translation",
"name": "Protein Translation",
Expand Down
34 changes: 34 additions & 0 deletions exercises/practice/phone-number/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Instructions

Clean up user-entered phone numbers so that they can be sent SMS messages.

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.
All NANP-countries share the same international country code: `1`.

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.
The first three digits of the local number represent the _exchange code_, followed by the unique four-digit number which is the _subscriber number_.

The format is usually represented as

```text
NXX NXX-XXXX
```

where `N` is any digit from 2 through 9 and `X` is any digit from 0 through 9.

Sometimes they also have the country code (represented as `1` or `+1`) prefixed.

Your task is to clean up differently formatted telephone numbers by removing punctuation and the country code if present.

For example, the inputs

- `+1 (613)-995-0253`
- `613-995-0253`
- `1 613 995 0253`
- `613.995.0253`

should all produce the output

`6139950253`

**Note:** As this exercise only deals with telephone numbers used in NANP-countries, only 1 is considered a valid country code.
30 changes: 30 additions & 0 deletions exercises/practice/phone-number/.meta/Example.roc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
module [clean]

clean : Str -> Result Str [InvalidNumber]
clean = \phoneNumber ->
digits =
phoneNumber
|> Str.toUtf8
|> List.keepIf \c -> c >= '0' && c <= '9'

numDigits = List.len digits
if numDigits == 10 then
digits |> checkNumber
else if numDigits == 11 then
when digits is
['1', .. as rest] -> rest |> checkNumber
_ -> Err InvalidNumber
else
Err InvalidNumber

checkNumber : List U8 -> Result Str [InvalidNumber]
checkNumber = \digits ->
areaStart = digits |> List.get 0 |> Result.withDefault '0'
exchangeStart = digits |> List.get 3 |> Result.withDefault '0'
if areaStart == '0' || areaStart == '1' || exchangeStart == '0' || exchangeStart == '1' then
Err InvalidNumber
else

when digits |> Str.fromUtf8 is
Ok number -> Ok number
Err (BadUtf8 _ _) -> crash "Unreachable: a string of digits is valid UTF8"
19 changes: 19 additions & 0 deletions exercises/practice/phone-number/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"authors": [
"ageron"
],
"files": {
"solution": [
"PhoneNumber.roc"
],
"test": [
"phone-number-test.roc"
],
"example": [
".meta/Example.roc"
]
},
"blurb": "Clean up user-entered phone numbers so that they can be sent SMS messages.",
"source": "Exercise by the JumpstartLab team for students at The Turing School of Software and Design.",
"source_url": "https://turing.edu"
}
18 changes: 18 additions & 0 deletions exercises/practice/phone-number/.meta/template.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{%- import "generator_macros.j2" as macros with context -%}
{{ macros.canonical_ref() }}
{{ macros.header() }}

import {{ exercise | to_pascal }} exposing [{{ cases[0]["property"] | to_camel }}]

{% for case in cases -%}
# {{ case["description"] }}
expect
result = {{ case["property"] | to_camel }} {{ case["input"]["phrase"] | to_roc }}
{%- if case["expected"]["error"] %}
result |> Result.isErr
{%- else %}
expected = Ok {{ case["expected"] | to_roc }}
result == expected
{%- endif %}

{% endfor %}
84 changes: 84 additions & 0 deletions exercises/practice/phone-number/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# This is an auto-generated file.
#
# Regenerating this file via `configlet sync` will:
# - Recreate every `description` key/value pair
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
# - Preserve any other key/value pair
#
# As user-added comments (using the # character) will be removed when this file
# is regenerated, comments can be added via a `comment` key.

[79666dce-e0f1-46de-95a1-563802913c35]
description = "cleans the number"

[c360451f-549f-43e4-8aba-fdf6cb0bf83f]
description = "cleans numbers with dots"

[08f94c34-9a37-46a2-a123-2a8e9727395d]
description = "cleans numbers with multiple spaces"

[598d8432-0659-4019-a78b-1c6a73691d21]
description = "invalid when 9 digits"
include = false

[2de74156-f646-42b5-8638-0ef1d8b58bc2]
description = "invalid when 9 digits"
reimplements = "598d8432-0659-4019-a78b-1c6a73691d21"

[57061c72-07b5-431f-9766-d97da7c4399d]
description = "invalid when 11 digits does not start with a 1"

[9962cbf3-97bb-4118-ba9b-38ff49c64430]
description = "valid when 11 digits and starting with 1"

[fa724fbf-054c-4d91-95da-f65ab5b6dbca]
description = "valid when 11 digits and starting with 1 even with punctuation"

[c6a5f007-895a-4fc5-90bc-a7e70f9b5cad]
description = "invalid when more than 11 digits"
include = false

[4a1509b7-8953-4eec-981b-c483358ff531]
description = "invalid when more than 11 digits"
reimplements = "c6a5f007-895a-4fc5-90bc-a7e70f9b5cad"

[63f38f37-53f6-4a5f-bd86-e9b404f10a60]
description = "invalid with letters"
include = false

[eb8a1fc0-64e5-46d3-b0c6-33184208e28a]
description = "invalid with letters"
reimplements = "63f38f37-53f6-4a5f-bd86-e9b404f10a60"

[4bd97d90-52fd-45d3-b0db-06ab95b1244e]
description = "invalid with punctuations"
include = false

[065f6363-8394-4759-b080-e6c8c351dd1f]
description = "invalid with punctuations"
reimplements = "4bd97d90-52fd-45d3-b0db-06ab95b1244e"

[d77d07f8-873c-4b17-8978-5f66139bf7d7]
description = "invalid if area code starts with 0"

[c7485cfb-1e7b-4081-8e96-8cdb3b77f15e]
description = "invalid if area code starts with 1"

[4d622293-6976-413d-b8bf-dd8a94d4e2ac]
description = "invalid if exchange code starts with 0"

[4cef57b4-7d8e-43aa-8328-1e1b89001262]
description = "invalid if exchange code starts with 1"

[9925b09c-1a0d-4960-a197-5d163cbe308c]
description = "invalid if area code starts with 0 on valid 11-digit number"

[3f809d37-40f3-44b5-ad90-535838b1a816]
description = "invalid if area code starts with 1 on valid 11-digit number"

[e08e5532-d621-40d4-b0cc-96c159276b65]
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"
5 changes: 5 additions & 0 deletions exercises/practice/phone-number/PhoneNumber.roc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module [clean]

clean : Str -> Result Str _
clean = \phoneNumber ->
crash "Please implement the 'clean' function"
107 changes: 107 additions & 0 deletions exercises/practice/phone-number/phone-number-test.roc
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# These tests are auto-generated with test data from:
# https://github.com/exercism/problem-specifications/tree/main/exercises/phone-number/canonical-data.json
# File last updated on 2024-10-09
app [main] {
pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.tar.br",
}

main =
Task.ok {}

import PhoneNumber exposing [clean]

# cleans the number
expect
result = clean "(223) 456-7890"
expected = Ok "2234567890"
result == expected

# cleans numbers with dots
expect
result = clean "223.456.7890"
expected = Ok "2234567890"
result == expected

# cleans numbers with multiple spaces
expect
result = clean "223 456 7890 "
expected = Ok "2234567890"
result == expected

# invalid when 9 digits
expect
result = clean "123456789"
result |> Result.isErr

# invalid when 11 digits does not start with a 1
expect
result = clean "22234567890"
result |> Result.isErr

# valid when 11 digits and starting with 1
expect
result = clean "12234567890"
expected = Ok "2234567890"
result == expected

# valid when 11 digits and starting with 1 even with punctuation
expect
result = clean "+1 (223) 456-7890"
expected = Ok "2234567890"
result == expected

# invalid when more than 11 digits
expect
result = clean "321234567890"
result |> Result.isErr

# invalid with letters
expect
result = clean "523-abc-7890"
result |> Result.isErr

# invalid with punctuations
expect
result = clean "523-@:!-7890"
result |> Result.isErr

# invalid if area code starts with 0
expect
result = clean "(023) 456-7890"
result |> Result.isErr

# invalid if area code starts with 1
expect
result = clean "(123) 456-7890"
result |> Result.isErr

# invalid if exchange code starts with 0
expect
result = clean "(223) 056-7890"
result |> Result.isErr

# invalid if exchange code starts with 1
expect
result = clean "(223) 156-7890"
result |> Result.isErr

# invalid if area code starts with 0 on valid 11-digit number
expect
result = clean "1 (023) 456-7890"
result |> Result.isErr

# invalid if area code starts with 1 on valid 11-digit number
expect
result = clean "1 (123) 456-7890"
result |> Result.isErr

# invalid if exchange code starts with 0 on valid 11-digit number
expect
result = clean "1 (223) 056-7890"
result |> Result.isErr

# invalid if exchange code starts with 1 on valid 11-digit number
expect
result = clean "1 (223) 156-7890"
result |> Result.isErr

0 comments on commit e5cd967

Please sign in to comment.