Validate and Format Phone Numbers into E.164
• kotlinstringsvalidationfunctionsbeginnerformatting
Hook: Phone numbers show up in every app, but users type them in all kinds of messy formats. Your job is to clean and standardize them.
Problem statement: Write a Kotlin function that converts a raw phone number string into an E.164-style format: a leading + followed by digits only. The function must validate input and return a clear error message when invalid.
Input/Output:
Input: raw (String), defaultCountryCode (String, optional).
Output: A String that is either a formatted phone like +639171234567 or an error message starting with Error:.
Example:raw = "0917-123-4567", defaultCountryCode = "63" → +6309171234567 is not allowed because it keeps the leading 0 after normalization; your function should instead decide how to normalize by digits-only rules and constraints.
For this challenge, treat any non-+ input as local digits and prepend the default country code to the digits you extracted.
Rules/Constraints:
- Trim whitespace before processing.
- Allow at most one
+, and only if it is the first character. - Ignore punctuation and spaces by extracting digits only.
- Digits length before normalization must be between 10 and 15 inclusive.
- If the input starts with
+, treat extracted digits as the full international number. - If the input does not start with
+, prependdefaultCountryCodeto the extracted digits. - After normalization, total digits must still be between 10 and 15 inclusive.
- After normalization, the number must not start with
0. - On invalid input, return a message that begins with
Error:and clearly explains the problem.
Try it yourself: Implement the function and test it with inputs like "+63 (917) 123 4567", "9171234567", "++63 917 123 4567", and "". Print the result for each one.
Hints:
- Count how many times
+appears and where it appears. - Use
filter { it.isDigit() }to remove punctuation. - Validate length both before and after adding the country code.
Step-by-step approach (high-level):
- Trim the input and reject empty strings.
- Validate
+placement (only once, only at the start). - Extract digits-only from the input.
- Validate digit count (10–15) before normalization.
- If no leading
+, prepend the default country code. - Validate digit count again and ensure it doesn’t start with
0. - Return the final formatted string with a single leading
+.
Edge cases:
- Empty input or whitespace-only input.
+appearing in the middle (e.g.,"12+345").- Too few or too many digits after stripping punctuation.
- Normalized numbers that start with
0.
Time/space complexity: O(n) time to scan the string and extract digits, O(n) space for the filtered digits string.
Starter function signature:
fun formatToE164(raw: String, defaultCountryCode: String = "63"): String
Solution
fun formatToE164(raw: String, defaultCountryCode: String = "63"): String {
val input = raw.trim()
if (input.isEmpty()) return "Error: input is empty"
val plusCount = input.count { it == '+' }
if (plusCount > 1) return "Error: '+' may appear at most once"
if (plusCount == 1 && !input.startsWith("+")) return "Error: '+' must be the first character"
if (defaultCountryCode.isBlank()) return "Error: default country code is empty"
if (!defaultCountryCode.all { it.isDigit() }) return "Error: default country code must contain digits only"
if (defaultCountryCode.startsWith("0")) return "Error: default country code must not start with 0"
val digitsOnly = input.filter { it.isDigit() }
if (digitsOnly.length < 10 || digitsOnly.length > 15) {
return "Error: phone must have 10 to 15 digits after removing punctuation"
}
val normalizedDigits = if (input.startsWith("+")) {
digitsOnly
} else {
defaultCountryCode + digitsOnly
}
if (normalizedDigits.length < 10 || normalizedDigits.length > 15) {
return "Error: normalized phone must have 10 to 15 digits"
}
if (normalizedDigits.startsWith("0")) {
return "Error: phone cannot start with 0 after normalization"
}
return "+$normalizedDigits"
}
fun main() {
val samples = listOf(
"0917-123-4567",
"+63 (917) 123 4567",
"917 123 4567",
"++63 917 123 4567",
"12-34",
" ",
"+0 917 123 4567"
)
for (s in samples) {
println("$s -> ${formatToE164(s)}")
}
}
// Sample output:
// 0917-123-4567 -> Error: normalized phone must have 10 to 15 digits

