9

I've got a DB chock full o' phone numbers as strings, they're all formatted like 1112223333, I'd like to display it as 111-222-3333 in my django template

I know I can do

n = contacts.objects.get(name=name)
n.phone = n.phone[:3] + '-' + n.phone[3:6] + '-' + n.phone[6:]

but is there a better / more pythonic way?

JKirchartz
  • 17,612
  • 7
  • 60
  • 88

5 Answers5

13

It may be overkill for your use case if all your numbers are formatted the same way, but you might consider using the phonenumbers module. It would allow you to add functionality (e.g. international phone numbers, different formatting, etc) very easily.

You can parse your numbers like this:

>>> import phonenumbers
>>> parsed_number = phonenumbers.parse('1112223333', 'US')
>>> parsed_number
PhoneNumber(country_code=1, national_number=1112223333L, extension=None, italian_leading_zero=False, country_code_source=None, preferred_domestic_carrier_code=None)

Then, to format it the way you want, you could do this:

>>> phonenumbers.format_number(parsed_number, phonenumbers.PhoneNumber())
u'111-222-3333'

Note that you could easily use other formats:

>>> phonenumbers.format_number(parsed_number, phonenumbers.PhoneNumberFormat.NATIONAL)
u'(111) 222-3333'
>>> phonenumbers.format_number(parsed_number, phonenumbers.PhoneNumberFormat.INTERNATIONAL)
u'+1 111-222-3333'
>>> phonenumbers.format_number(parsed_number, phonenumbers.PhoneNumberFormat.E164)
u'+11112223333'
jterrace
  • 64,866
  • 22
  • 157
  • 202
  • 1
    I'm using it, despite the overkill, because the package looks solid and I think it can do a little better job of validation than I'm doing now. My issue started with formatting, but it looks like it'll have other benefits. – Dustin Rasener Jan 07 '13 at 16:29
  • Also, the "Format as you type" thing sounds pretty useful. – Dustin Rasener Jan 07 '13 at 16:36
9

This is quite a bit belated, but I figured I'd post my solution anyway. It's super simple and takes advantage of creating your own template tags (for use throughout your project). The other part of this is using the parenthesis around the area code.

from django import template
register = template.Library()

def phonenumber(value):
    phone = '(%s) %s - %s' %(value[0:3],value[3:6],value[6:10])
    return phone

register.filter('phonenumber', phonenumber)

For the rest of your project, all you need to do is {{ var|phonenumber }}

ChrisGPT was on strike
  • 127,765
  • 105
  • 273
  • 257
Alex Koziak
  • 101
  • 1
  • 3
8

Just one other solution:

n.phone = "%c%c%c-%c%c%c-%c%c%c%c" % tuple(map(ord, n.phone))

or

n.phone = "%s%s%s-%s%s%s-%s%s%s%s" % tuple(n.phone)
rumpel
  • 7,870
  • 2
  • 38
  • 39
7

Since we're speaking Pythonic :), it's a good habit to always use join instead of addition (+) to join strings:

phone = n.phone
n.phone = '-'.join((phone[:3],phone[3:6],phone[6:]))
Community
  • 1
  • 1
unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
2
def formatPhone(phone):
    formatted = ''
    i = 0

    # clean phone. skip not digits
    phone = ''.join(x for x in phone if x.isdigit())

    # set pattern
    if len(phone) > 10:
        pattern = 'X (XXX) XXX-XX-XX'
    else:
        pattern = 'XXX-XXX-XX-XX'

    # reverse
    phone = phone[::-1]
    pattern = pattern[::-1]

    # scan pattern
    for p in pattern:
        if i >= len(phone):
            break

        # skip non X
        if p != 'X':
            formatted += p
            continue        

        # add phone digit
        formatted += phone[i]
        i += 1

    # reverse again    
    formatted = formatted[::-1]

    return formatted

print formatPhone('+7-111-222-33-44')

7 (111) 222-33-44

print formatPhone('222-33-44')

222-33-44

print formatPhone('23344')

2-33-44

Vitaly Fadeev
  • 886
  • 10
  • 13