🎉 Exercism Research is now launched. Help Exercism, help science and have some fun at research.exercism.io 🎉
Avatar of thekeele

thekeele's solution

to Phone Number in the Elixir Track

Published at May 08 2019 · 0 comments
Instructions
Test suite
Solution

Note:

This exercise has changed since this solution was written.

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

(NXX)-NXX-XXXX

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

Your task is to clean up differently formatted telephone numbers by removing punctuation and the country code (1) 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.

Running tests

Execute the tests with:

$ elixir phone_number_test.exs

Pending tests

In the test suites, all but the first test have been skipped.

Once you get a test passing, you can unskip the next one by commenting out the relevant @tag :pending with a # symbol.

For example:

# @tag :pending
test "shouting" do
  assert Bob.hey("WATCH OUT!") == "Whoa, chill out!"
end

Or, you can enable all the tests by commenting out the ExUnit.configure line in the test suite.

# ExUnit.configure exclude: :pending, trace: true

If you're stuck on something, it may help to look at some of the available resources out there where answers might be found.

Source

Event Manager by JumpstartLab http://tutorials.jumpstartlab.com/projects/eventmanager.html

Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

phone_number_test.exs

if !System.get_env("EXERCISM_TEST_EXAMPLES") do
  Code.load_file("phone_number.exs", __DIR__)
end

ExUnit.start()
ExUnit.configure(exclude: :pending, trace: true)

defmodule PhoneTest do
  use ExUnit.Case

  test "cleans number" do
    assert Phone.number("(212) 555-0100") == "2125550100"
  end

  @tag :pending
  test "cleans number with dots" do
    assert Phone.number("212.555.0100") == "2125550100"
  end

  @tag :pending
  test "valid when 11 digits and first is 1" do
    assert Phone.number("12125550100") == "2125550100"
  end

  @tag :pending
  test "valid when 11 digits and some decorations" do
    assert Phone.number("+1 (212) 555-0100") == "2125550100"
  end

  @tag :pending
  test "invalid when country calling code is not 1" do
    assert Phone.number("22125550100") == "0000000000"
  end

  @tag :pending
  test "invalid when 9 digits" do
    assert Phone.number("212555010") == "0000000000"
  end

  @tag :pending
  test "invalid when proper number of digits but letters mixed in" do
    assert Phone.number("2a1a2a5a5a5a0a1a0a0a") == "0000000000"
  end

  @tag :pending
  test "invalid with correct number of characters but some are letters" do
    assert Phone.number("2a1a2a5a5a") == "0000000000"
  end

  @tag :pending
  test "invalid when area code begins with 1" do
    assert Phone.number("1125550100") == "0000000000"
  end

  @tag :pending
  test "invalid when area code begins with 0" do
    assert Phone.number("0125550100") == "0000000000"
  end

  @tag :pending
  test "invalid when exchange code begins with 1" do
    assert Phone.number("2121550100") == "0000000000"
  end

  @tag :pending
  test "invalid when exchange code begins with 0" do
    assert Phone.number("2120550100") == "0000000000"
  end

  @tag :pending
  test "area code" do
    assert Phone.area_code("2125550100") == "212"
  end

  @tag :pending
  test "area code with full US phone number" do
    assert Phone.area_code("12125550100") == "212"
  end

  @tag :pending
  test "invalid area code" do
    assert Phone.area_code("(100) 555-1234") == "000"
  end

  @tag :pending
  test "no area code" do
    assert Phone.area_code("867.5309") == "000"
  end

  @tag :pending
  test "pretty print" do
    assert Phone.pretty("2125550100") == "(212) 555-0100"
  end

  @tag :pending
  test "pretty print with full US phone number" do
    assert Phone.pretty("+1 (303) 555-1212") == "(303) 555-1212"
  end

  @tag :pending
  test "pretty print invalid US phone number" do
    assert Phone.pretty("212-155-0100") == "(000) 000-0000"
  end

  @tag :pending
  test "pretty print invalid, short US phone number" do
    assert Phone.pretty("867.5309") == "(000) 000-0000"
  end
end
defmodule Phone do
  @spec number(String.t()) :: String.t()
  def number(<<"+1 ">> <> nanp_number) do
    number(nanp_number)
  end
  def number(<<"1">> <> nanp_number) do
    number(nanp_number)
  end
  def number(<<"(", area_code::binary-size(3), ") ",
               exchange_code::binary-size(3), "-",
               subscriber_code::binary-size(4)>>) do
    number(area_code <> exchange_code <> subscriber_code)
  end
  def number(<<area_code::binary-size(3), ".",
               exchange_code::binary-size(3), ".",
               subscriber_code::binary-size(4)>>) do
    number(area_code <> exchange_code <> subscriber_code)
  end
  def number(<<"0", _::binary-size(9)>>) do
    "0000000000"
  end
  def number(<<_::binary-size(3), "0", _::binary-size(6)>>) do
    "0000000000"
  end
  def number(<<_::binary-size(3), "1", _::binary-size(6)>>) do
    "0000000000"
  end
  def number(<<nanp_number::binary-size(10)>>) do
    case Integer.parse(nanp_number) do
      {_, ""} -> nanp_number
      _ -> "0000000000"
    end
  end
  def number(_) do
    "0000000000"
  end

  @spec area_code(String.t()) :: String.t()
  def area_code(raw) do
    <<area_code::binary-size(3), _::binary-size(7)>> = number(raw)
    area_code
  end

  @spec pretty(String.t()) :: String.t()
  def pretty(raw) do
    <<ac::binary-size(3), ec::binary-size(3), sc::binary-size(4)>> = number(raw)
    "(#{ac}) #{ec}-#{sc}"
  end
end

Community comments

Find this solution interesting? Ask the author a question to learn more.

thekeele's Reflection

Any suggestions on how this solution could work WITHOUT Integer.parse/2?