Valid Phone Numbers
Problem
Print all valid phone numbers from file.txt. A valid phone number must look like (xxx) xxx-xxxx or xxx-xxx-xxxx where x is a digit. Each line of the file contains a single string. Canonical bash: grep -E '^([0-9]{3}-|\(([0-9]{3})\) )[0-9]{3}-[0-9]{4}$' file.txt.
987-123-4567\n123 456 7890\n(001) 345-0000987-123-4567\n(001) 345-0000# Bash one-liner:
# grep -E '^([0-9]{3}-|\([0-9]{3}\) )[0-9]{3}-[0-9]{4}$' file.txt
import re
PHONE = re.compile(r'^(\d{3}-|\(\d{3}\) )\d{3}-\d{4}$')
def valid_phone_numbers(lines):
return [ln for ln in lines if PHONE.match(ln)]
// Bash one-liner:
// grep -E '^([0-9]{3}-|\([0-9]{3}\) )[0-9]{3}-[0-9]{4}$' file.txt
const PHONE = /^(\d{3}-|\(\d{3}\) )\d{3}-\d{4}$/;
function validPhoneNumbers(lines) {
return lines.filter(ln => PHONE.test(ln));
}
// Bash one-liner:
// grep -E '^([0-9]{3}-|\([0-9]{3}\) )[0-9]{3}-[0-9]{4}$' file.txt
class Solution {
static final Pattern PHONE = Pattern.compile(
"^(\\d{3}-|\\(\\d{3}\\) )\\d{3}-\\d{4}$"
);
public List<String> validPhoneNumbers(List<String> lines) {
List<String> out = new ArrayList<>();
for (String ln : lines) if (PHONE.matcher(ln).matches()) out.add(ln);
return out;
}
}
// Bash one-liner:
// grep -E '^([0-9]{3}-|\([0-9]{3}\) )[0-9]{3}-[0-9]{4}$' file.txt
#include <regex>
static const regex PHONE("^(\\d{3}-|\\(\\d{3}\\) )\\d{3}-\\d{4}$");
vector<string> validPhoneNumbers(vector<string>& lines) {
vector<string> out;
for (auto& ln : lines) if (regex_match(ln, PHONE)) out.push_back(ln);
return out;
}
Explanation
We only need to print the lines that look like valid phone numbers, and a regular expression is the perfect tool: it describes the exact shape we accept and rejects everything else in one shot.
The pattern is ^(\d{3}-|\(\d{3}\) )\d{3}-\d{4}$. The ^ and $ anchor it to the whole line so there is no extra junk. The first group allows two openings: either three digits and a dash (123-), or three digits in parentheses followed by a space ((123) ).
After that opening, \d{3}-\d{4} requires three digits, a dash, then four digits. So both xxx-xxx-xxxx and (xxx) xxx-xxxx are accepted, and nothing else is.
The code simply filters the lines, keeping each one where the regex matches. The bash equivalent is the same idea with grep -E printing matching lines.
Example: 987-123-4567 matches the dash form, and (001) 345-0000 matches the parenthesis form, so both are printed. 123 456 7890 uses spaces instead of the required dashes, so it fails the pattern and is dropped.