开发者

Perl: Format US phone number based on input

This didn't answer my question.

Possible开发者_JS百科 inputs (may have whitespace):

  • full number: (XXX) XXX-XXXX
  • full number: XXX/XXX-XXXX
  • full number: XXXXXXXXXX
  • no area code: XXX-XXXX
  • no area code: XXXXXXX
  • extension only: XXXX

So if you regex it for digits only s/[^\d]//g, you'll hopefully get 1 of 3 options:

  • XXXXXXXXXX
  • XXXXXXX
  • XXXX

Which I would like to format as so:

  • XXX/XXX-XXXX
  • XXX-XXXX
  • XXXX

Is the best way to do this to do if statements based on the length? Or is there a more one-liner approach?


I'd just use if statements, because they're a lot clearer and easier to extend:

if (length($number) == 4) {
  # extension
} elsif (length($number) == 7) {
  # no area code
} elsif (length($number) == 10) {
  # full number
} else {
  die "unsupported number";
}

If you're using Perl 5.10 or higher, you can use the switch:

use feature "switch";

given (length($number) {
  when (4) { # extension }
  when (7) { # no area code }
  when (10) { # full number }
  default { die "unsupported number"; }
}

Either of these give the advantage of being easily modified to, for example, take a number that starts with 1 (i.e. 1-555-123-4567).


You can use a sequence of substitutions.

s#[^\d]##g;
s#(\d{3})(\d{4})$#$1-$2#;
s#(\d{3})(\d{3})-#$1/$2-#;

The second substitution will fail (i.e., have no effect) if the input has less than 7 digits, and the third substitution will fail if the input has less than 10 digits.


This should do it:

perl -pne's;(?:\(?(\d{3})[\)/]?\s*)?(?:(\d{3})-?)?(\d{4});$1/$2-$3;||die("bad #: $_") and s;^/-?;;'

Example:

$ echo "(123)456-7890
(123) 456-7890
123/456-7890
1234567890
456-7890
7890
foobar
" |perl -pne's;(?:\(?(\d{3})[\)/]?\s*)?(?:(\d{3})-?)?(\d{4});$1/$2-$3;||die("bad #: $_") and s;^/-?;;'
123/456-7890
123/456-7890
123/456-7890
123/456-7890
456-7890
7890
bad number: foobar at -e line 1, <> line 7.


CodePad

sub phoneFormat{
    my @sigils  = ('+','/','-');            # joiners
    $_ = reverse(shift);                    # input; reversed for matches
    @_ = grep{defined} unpack "A4A3A3A1",$_;    # match, starting with extension; and remove unmatched
    $_ = join('', map {$_ . pop @sigils } @_ ); # add in the delimiters
    ($_ = reverse) =~ s/^[^\d]+//;          # reverse back and remove leading non-digits
    $_;
}

print phoneFormat('012')         , "\n";    # (blank)
print phoneFormat('0123')        , "\n";    # 0123
print phoneFormat('0123456')     , "\n";    # 012-3456
print phoneFormat('0123456789')  , "\n";    # 012/345-6789
print phoneFormat('01234567899') , "\n";    # 0+123/456-7899
print phoneFormat('012345678999') , "\n";   # 1+234/567-8999


for(<DATA>){
  /^.*?: \s* \(? (\d{3})?? [)\/]? \s* (\d{3})? \s* [-]? \s* (\d{4}) \s* $/x;
  print "$&\t";
  print "$1 / " if $1;
  print "$2 - " if $2;
  print "$3\n"  if $3;      
}


__DATA__
* full number: (123) 456-7890
* full number: 123/456-7890
* full number: 1234567890
* no area code: 456-7890
* no area code: 4567890
* extension only: 7890

OUTPUT

* full number: (123) 456-7890
123 / 456 - 7890
* full number: 123/456-7890
123 / 456 - 7890
* full number: 1234567890
123 / 456 - 7890
* no area code: 456-7890
456 - 7890
* no area code: 4567890
456 - 7890
* extension only: 7890
7890

You could also use named captures like (?<area>\d{3}) to increase readability!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜