How about a custom object that encapsulates checking and formatting?
function BelgianPhoneNumber(inputStr) {
var re = /0{0,3}32(?:(9[23]|8[0-79|7[1]|6[0-579]|5[0-9]|2[2568]|1[0-69])([0-9]{2})|([2-9])([0-9]{3}))([0-9]{2})([0-9]{2})/,
match, area, grp1, grp2, grp3;
if (match = re.exec(inputStr)) {
if (match[1]) {
area = match[1];
grp1 = match[2];
} else {
area = match[3];
grp1 = match[4];
}
grp3 = match[5];
grp4 = match[6];
} else {
area = grp1 = grp2 = grp3 = "";
// possibly throw error
}
this.toString = function () {
if (match) {
return ["+32", area, grp1, grp2, grp3].join(" ");
} else {
return "invalid phone number: " + inputStr;
}
}
}
Usage
var p = new BelgianPhoneNumber("003233437667");
console.log("Phone: " + p); // -> Phone: +32 3 343 76 67
var p = new BelgianPhoneNumber("003287565656")
console.log("Phone: " + p); // -> Phone: +32 87 56 56 56
I have no idea whether the two numbering schemas can overlap, though, yielding false positives when matching.
However, when in doubt the regex favors 2-digit area codes over 1-digit ones. If you want it the other way around, change the order of the "choice..." group.
An argument for a custom object is that you could easily add methods like .getAreaCode() or one that maps area codes to city names. And you would still be able to use it directly in a string, thanks to the overridden .toString() method.
The combined regex breaks down as
0{0,3}32 # constant prefix, therefore no group
(?: # choice: either...
(9[23]|8[0-79|7[1]|6[0-579]|5[0-9]|2[2568]|1[0-69]) # 2-digit area code
([0-9]{2}) # first group (2 digits)
| # or...
([2-9]) # 1-digit area code
([0-9]{3}) # first group (3 digits)
) # end choice
([0-9]{2}) # second group (2 digits)
([0-9]{2}) # third group (2 digits)