From 4088d137c646c274949647ebba6c1e52206c6de5 Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Sat, 1 Feb 2025 21:44:58 +1100 Subject: [PATCH] Add phone-number exercise --- config.json | 8 ++ .../phone-number/.docs/instructions.md | 34 ++++++ .../phone-number/.docs/introduction.md | 12 ++ .../practice/phone-number/.meta/config.json | 19 +++ .../practice/phone-number/.meta/example.zig | 38 ++++++ .../practice/phone-number/.meta/tests.toml | 84 +++++++++++++ .../practice/phone-number/phone_number.zig | 4 + .../phone-number/test_phone_number.zig | 112 ++++++++++++++++++ 8 files changed, 311 insertions(+) create mode 100644 exercises/practice/phone-number/.docs/instructions.md create mode 100644 exercises/practice/phone-number/.docs/introduction.md create mode 100644 exercises/practice/phone-number/.meta/config.json create mode 100644 exercises/practice/phone-number/.meta/example.zig create mode 100644 exercises/practice/phone-number/.meta/tests.toml create mode 100644 exercises/practice/phone-number/phone_number.zig create mode 100644 exercises/practice/phone-number/test_phone_number.zig diff --git a/config.json b/config.json index 2349f29a..01da1cd8 100644 --- a/config.json +++ b/config.json @@ -270,6 +270,14 @@ "prerequisites": [], "difficulty": 4 }, + { + "slug": "phone-number", + "name": "Phone Number", + "uuid": "66cd0755-1817-4ae3-9c5f-fab39bb08065", + "practices": [], + "prerequisites": [], + "difficulty": 3 + }, { "slug": "isogram", "name": "Isogram", diff --git a/exercises/practice/phone-number/.docs/instructions.md b/exercises/practice/phone-number/.docs/instructions.md new file mode 100644 index 00000000..62ba48e9 --- /dev/null +++ b/exercises/practice/phone-number/.docs/instructions.md @@ -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. diff --git a/exercises/practice/phone-number/.docs/introduction.md b/exercises/practice/phone-number/.docs/introduction.md new file mode 100644 index 00000000..c4142c5a --- /dev/null +++ b/exercises/practice/phone-number/.docs/introduction.md @@ -0,0 +1,12 @@ +# Introduction + +You've joined LinkLine, a leading communications company working to ensure reliable connections for everyone. +The team faces a big challenge: users submit phone numbers in all sorts of formats — dashes, spaces, dots, parentheses, and even prefixes. +Some numbers are valid, while others are impossible to use. + +Your mission is to turn this chaos into order. +You'll clean up valid numbers, formatting them appropriately for use in the system. +At the same time, you'll identify and filter out any invalid entries. + +The success of LinkLine's operations depends on your ability to separate the useful from the unusable. +Are you ready to take on the challenge and keep the connections running smoothly? diff --git a/exercises/practice/phone-number/.meta/config.json b/exercises/practice/phone-number/.meta/config.json new file mode 100644 index 00000000..f85e9216 --- /dev/null +++ b/exercises/practice/phone-number/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "phone_number.zig" + ], + "test": [ + "test_phone_number.zig" + ], + "example": [ + ".meta/example.zig" + ] + }, + "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" +} diff --git a/exercises/practice/phone-number/.meta/example.zig b/exercises/practice/phone-number/.meta/example.zig new file mode 100644 index 00000000..25a13b93 --- /dev/null +++ b/exercises/practice/phone-number/.meta/example.zig @@ -0,0 +1,38 @@ +pub fn clean(phrase: []const u8) ?[10]u8 { + var result: [10]u8 = undefined; + var leading_one = false; + var index: usize = 0; + for (phrase) |digit| { + if (digit < '0') { + // Ignore whitespace and ( ) + - + continue; + } + + if (digit > '9') { + // Reject letters and punctuation like @ + return null; + } + + if (index == 0 and digit == '1') { + if (leading_one) { + return null; + } + + leading_one = true; + continue; + } + + if (index == 10) { + return null; + } + + result[index] = digit; + index += 1; + } + + if (index != 10 or result[0] < '2' or result[3] < '2') { + return null; + } + + return result; +} diff --git a/exercises/practice/phone-number/.meta/tests.toml b/exercises/practice/phone-number/.meta/tests.toml new file mode 100644 index 00000000..24dbf07a --- /dev/null +++ b/exercises/practice/phone-number/.meta/tests.toml @@ -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" diff --git a/exercises/practice/phone-number/phone_number.zig b/exercises/practice/phone-number/phone_number.zig new file mode 100644 index 00000000..fd913763 --- /dev/null +++ b/exercises/practice/phone-number/phone_number.zig @@ -0,0 +1,4 @@ +pub fn clean(phrase: []const u8) ?[10]u8 { + _ = phrase; + @compileError("please implement the clean function"); +} diff --git a/exercises/practice/phone-number/test_phone_number.zig b/exercises/practice/phone-number/test_phone_number.zig new file mode 100644 index 00000000..885b1c73 --- /dev/null +++ b/exercises/practice/phone-number/test_phone_number.zig @@ -0,0 +1,112 @@ +const std = @import("std"); +const testing = std.testing; + +const phone_number = @import("phone_number.zig"); + +test "cleans the number" { + const expected: ?[10]u8 = "2234567890".*; + const actual = phone_number.clean("(223) 456-7890"); + try testing.expectEqual(expected, actual); +} + +test "cleans numbers with dots" { + const expected: ?[10]u8 = "2234567890".*; + const actual = phone_number.clean("223.456.7890"); + try testing.expectEqual(expected, actual); +} + +test "cleans numbers with multiple spaces" { + const expected: ?[10]u8 = "2234567890".*; + const actual = phone_number.clean("223 456 7890 "); + try testing.expectEqual(expected, actual); +} + +test "invalid when 9 digits" { + const expected: ?[10]u8 = null; + const actual = phone_number.clean("123456789"); + try testing.expectEqual(expected, actual); +} + +test "invalid when 11 digits does not start with a 1" { + const expected: ?[10]u8 = null; + const actual = phone_number.clean("22234567890"); + try testing.expectEqual(expected, actual); +} + +test "valid when 11 digits and starting with 1" { + const expected: ?[10]u8 = "2234567890".*; + const actual = phone_number.clean("12234567890"); + try testing.expectEqual(expected, actual); +} + +test "valid when 11 digits and starting with 1 even with punctuation" { + const expected: ?[10]u8 = "2234567890".*; + const actual = phone_number.clean("+1 (223) 456-7890"); + try testing.expectEqual(expected, actual); +} + +test "invalid when more than 11 digits" { + const expected: ?[10]u8 = null; + const actual = phone_number.clean("321234567890"); + try testing.expectEqual(expected, actual); +} + +test "invalid with letters" { + const expected: ?[10]u8 = null; + const actual = phone_number.clean("523-abc-7890"); + try testing.expectEqual(expected, actual); +} + +test "invalid with punctuations" { + const expected: ?[10]u8 = null; + const actual = phone_number.clean("523-@:!-7890"); + try testing.expectEqual(expected, actual); +} + +test "invalid if area code starts with 0" { + const expected: ?[10]u8 = null; + const actual = phone_number.clean("(023) 456-7890"); + try testing.expectEqual(expected, actual); +} + +test "invalid if area code starts with 1" { + const expected: ?[10]u8 = null; + const actual = phone_number.clean("(123) 456-7890"); + try testing.expectEqual(expected, actual); +} + +test "invalid if exchange code starts with 0" { + const expected: ?[10]u8 = null; + const actual = phone_number.clean("(223) 056-7890"); + try testing.expectEqual(expected, actual); +} + +test "invalid if exchange code starts with 1" { + const expected: ?[10]u8 = null; + const actual = phone_number.clean("(223) 156-7890"); + try testing.expectEqual(expected, actual); +} + +test "invalid if area code starts with 0 on valid 11-digit number" { + const expected: ?[10]u8 = null; + const actual = phone_number.clean("1 (023) 456-7890"); + try testing.expectEqual(expected, actual); +} + +test "invalid if area code starts with 1 on valid 11-digit number" { + const expected: ?[10]u8 = null; + const actual = phone_number.clean("1 (123) 456-7890"); + try testing.expectEqual(expected, actual); +} + +test "invalid if exchange code starts with 0 on valid 11-digit number" { + const expected: ?[10]u8 = null; + const actual = phone_number.clean("1 (223) 056-7890"); + try testing.expectEqual(expected, actual); +} + +test "invalid if exchange code starts with 1 on valid 11-digit number" { + const expected: ?[10]u8 = null; + const actual = phone_number.clean("1 (223) 156-7890"); + try testing.expectEqual(expected, actual); +}