ðŸŽ‰ Exercism Research is now launched. Help Exercism, help science and have some fun at research.exercism.io ðŸŽ‰

# krukouskiandrei's solution

## to Phone Number in the Kotlin Track

Published at Oct 14 2020 · 0 comments
Instructions
Test suite
Solution

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.

## Setup

Go through the setup instructions for Kotlin to install the necessary dependencies:

https://exercism.io/tracks/kotlin/installation

## Making the test suite pass

Execute the tests with:

``````\$ gradlew test
``````

Use `gradlew.bat` if you're on Windows

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

Once you get a test passing, you can enable the next one by removing the `@Ignore` annotation.

## 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.

### PhoneNumberTest.kt

``````import org.junit.Ignore
import org.junit.Test
import java.lang.IllegalArgumentException
import kotlin.test.assertEquals
import kotlin.test.assertNull

class PhoneNumberTest {

@Test
fun `valid | simple number`() = assertNumberEquals("(223) 456-7890", "2234567890")

@Ignore
@Test
fun `valid | number with dots`() = assertNumberEquals("223.456.7890", "2234567890")

@Ignore
@Test
fun `valid | numbers with multiple spaces`() = assertNumberEquals("223 456   7890   ", "2234567890")

@Ignore
@Test(expected = IllegalArgumentException::class)
fun `invalid | 9 digit`() {
PhoneNumber("123456789")
}

@Ignore
@Test(expected = IllegalArgumentException::class)
fun `invalid | when 11 digits does not start with a 1`() {
PhoneNumber("22234567890")
}

@Ignore
@Test
fun `valid | 11 digits and starting with 1`() = assertNumberEquals("12234567890", "2234567890")

@Ignore
@Test
fun `valid | 11 digits starting with 1 with punctuation`() = assertNumberEquals("+1 (223) 456-7890", "2234567890")

@Ignore
@Test(expected = IllegalArgumentException::class)
fun `invalid | more than 11 digits`() {
PhoneNumber("321234567890")
}

@Ignore
@Test(expected = IllegalArgumentException::class)
fun `invalid | letters`() {
PhoneNumber("123-abc-7890")
}

@Ignore
@Test(expected = IllegalArgumentException::class)
fun `invalid | punctuations`() {
PhoneNumber("123-@:!-7890")
}

@Ignore
@Test(expected = IllegalArgumentException::class)
fun `invalid | area code starts with 0`() {
PhoneNumber("(023) 456-7890")
}

@Ignore
@Test(expected = IllegalArgumentException::class)
fun `invalid | area code starts with 1`() {
PhoneNumber("(123) 456-7890")
}

@Ignore
@Test(expected = IllegalArgumentException::class)
fun `invalid | exchange code starts with 0`() {
PhoneNumber("(223) 056-7890")
}

@Ignore
@Test(expected = IllegalArgumentException::class)
fun `invalid | exchange code starts with 1`() {
PhoneNumber("(223) 156-7890")
}

@Ignore
@Test(expected = IllegalArgumentException::class)
fun `invalid | area code starts with 0 on valid 11-digit number`() {
PhoneNumber("1 (023) 456-7890")
}

@Ignore
@Test(expected = IllegalArgumentException::class)
fun `invalid | area code starts with 1 on valid 11-digit number`() {
PhoneNumber("1 (123) 456-7890")
}

@Ignore
@Test(expected = IllegalArgumentException::class)
fun `invalid | exchange code starts with 0 on valid 11-digit number`() {
PhoneNumber("1 (223) 056-7890")
}

@Ignore
@Test(expected = IllegalArgumentException::class)
fun `invalid | exchange code starts with 1 on valid 11-digit number`() {
PhoneNumber("1 (223) 156-7890")
}
}

private fun assertNumberEquals(input: String, expectation: String) = assertEquals(expectation, PhoneNumber(input).number)``````
``````class PhoneNumber(private val input: String) {

val number: String? = createNumber()

private fun createNumber(): String? {
checkLettersInNumber()
checkPunctuationInNumber()

var number: String? = null

number = input.toList().filter { it.isDigit() }.joinToString("")

checkLengthOfNumber(number)
checkAreaCodeInNumber(number)
checkExchangeCode(number)

return if(number.startsWith("1")) number.substring(1) else number
}

private fun checkLengthOfNumber(number: String) {
if (number.length < 10) throw IllegalArgumentException("number should has at least 10 digits")
if (!number.startsWith("1") && number.length >= 11)
throw IllegalArgumentException("not valid number: incorrect length")
}

private fun checkLettersInNumber() {
val hasLetter = input.toList().filter { it.isLetter() }.any()
if (hasLetter) throw IllegalArgumentException("number shouldn't have letters")
}

private fun checkPunctuationInNumber() {
val hasPunctuation = input.toList()
.filter { !it.isLetterOrDigit() }
.filter { !it.isWhitespace() }
.filter { !it.isAllowedPunctuation()}
.any()
if (hasPunctuation) throw IllegalArgumentException("number shouldn't have punctuation")
}

fun Char.isAllowedPunctuation(): Boolean {
return when(this) {
'-', '(', ')', '.', '+' -> true
else -> false
}
}

private fun checkAreaCodeInNumber(number: String) {
val areaCode = if (number.length == 10) number.first() else number.removePrefix("1").first()
if (areaCode == '0' || areaCode == '1') throw IllegalArgumentException("not valid area code: \$areaCode")
}

private fun checkExchangeCode(number: String) {
val exchangeCode = if (number.length == 10) number.substring(3).first()
else number.substring(4).first()

if (exchangeCode == '0' || exchangeCode == '1')
throw IllegalArgumentException("not valid exchange code: \$exchangeCode")
}
}``````