package no.priv.garshol.duke.cleaners;
import java.util.Map;
import java.util.HashMap;
import no.priv.garshol.duke.Cleaner;
/**
* <p>Cleaner for international phone numbers. It assumes that it can
* get the same phone number in forms like:
*
* <ul>
* <li>0047 55301400
* <li>+47 55301400
* <li>47-55-301400
* <li>+47 (0) 55301400
* </ul>
*
* @since 1.0
*/
public class PhoneNumberCleaner implements Cleaner {
private Cleaner sub;
private static Map<String,CountryCode> ccodes = initcodes();
public PhoneNumberCleaner() {
this.sub = new DigitsOnlyCleaner();
}
// ALGORITHM:
// first look for + or 00. if they're there, then find country code.
// look for zero after country code, and remove if present
public String clean(String value) {
String orig = value;
// check if there's a + before the first digit
boolean initialplus = findPlus(value);
// remove everything but digits
value = sub.clean(value);
if (value == null)
return null;
// check for initial '00'
boolean zerozero = !initialplus && value.startsWith("00");
if (zerozero)
value = value.substring(2); // strip off the zeros
// look for country code
CountryCode ccode = findCountryCode(value);
if (ccode == null) {
// no country code, let's do what little we can
if (initialplus || zerozero)
return orig; // this number is messed up. dare not touch
return value;
} else {
value = value.substring(ccode.getPrefix().length()); // strip off ccode
if (ccode.getStripZero() && value.startsWith("0"))
value = value.substring(1); // strip the zero
if (ccode.isRightFormat(value))
return "+" + ccode.getPrefix() + " " + value;
else
return orig; // don't dare touch this
}
}
private CountryCode findCountryCode(String value) {
for (int ix = 1; ix < Math.min(4, value.length()); ix++) {
String code = value.substring(0, ix);
CountryCode ccode = ccodes.get(code);
if (ccode != null)
return ccode;
}
return null;
}
private boolean findPlus(String value) {
for (int ix = 0; ix < value.length(); ix++) {
char ch = value.charAt(ix);
if (ch == '+')
return true;
else if (ch >= '0' && ch <= '9')
return false;
}
return false;
}
static class CountryCode {
private String prefix;
private boolean strip_zero; // strip initial zero after country code
private int min_length; // length of phone numbers
private int max_length; // length of phone numbers
public CountryCode(String prefix) {
this(prefix, false);
}
public CountryCode(String prefix, int length) {
this(prefix, false, length);
}
public CountryCode(String prefix, boolean strip_zero) {
this(prefix, strip_zero, 0);
}
public CountryCode(String prefix, boolean strip_zero, int length) {
this.prefix = prefix;
this.strip_zero = strip_zero;
this.min_length = length;
this.max_length = length;
}
public CountryCode(String prefix, boolean strip_zero, int min_length,
int max_length) {
this.prefix = prefix;
this.strip_zero = strip_zero;
this.min_length = min_length;
this.max_length = max_length;
}
public String getPrefix() {
return prefix;
}
public boolean getStripZero() {
return strip_zero;
}
// returns true iff the phone number is in a correct format for
// this country.
public boolean isRightFormat(String value) {
if (max_length == 0)
return true; // anything can be right as far as we know
return value.length() >= min_length && value.length() <= max_length;
}
}
private static Map<String, CountryCode> initcodes() {
Map<String, CountryCode> ccs = new HashMap();
ccs.put("1", new CountryCode("1", false, 10)); // US
ccs.put("31", new CountryCode("31")); // Netherlands
ccs.put("33", new CountryCode("33")); // France
ccs.put("358", new CountryCode("358")); // Finland
ccs.put("44", new CountryCode("44", true)); // UK
ccs.put("45", new CountryCode("45", 8)); // Denmark
// http://sv.wikipedia.org/wiki/Telefonnummer
ccs.put("46", new CountryCode("46", true, 7, 9)); // Sweden
ccs.put("47", new CountryCode("47", true, 8)); // Norway
ccs.put("49", new CountryCode("49")); // Germany
// http://www.wtng.info/wtng-971-ae.html
ccs.put("971", new CountryCode("971", true, 7, 9)); // United Arab Emirates
return ccs;
}
}