Python,一种更智能的字符串到整数转换方式

时间:2010-03-23 12:53:27

标签: python string integer type-conversion

我编写了这段代码,将格式为“0(532)222 22 22”的字符串转换为整数,例如05322222222。

class Phone():
    def __init__(self,input):
        self.phone = input
    def __str__(self):
        return self.phone
    #convert to integer.
    def to_int(self):
        return int((self.phone).replace(" ","").replace("(","").replace(")",""))

test = Phone("0(532) 222 22 22")
print test.to_int()

使用3种替换方法来解决这个问题感觉非常笨拙。我很好奇是否有更好的解决方案?

4 个答案:

答案 0 :(得分:8)

p = "0(532) 222 22 22"
print ''.join([x for x in p if x.isdigit()])

请注意,如果要将其转换为int(就像标题中所建议的那样),您将“丢失”前导零。如果您想这样做,只需在int()电话中打包上述内容即可。虽然(在我看来)电话号码作为字符串更有意义。

答案 1 :(得分:6)

在Python 2.6或2.7中,
(self.phone).translate(None,' ()')
将从电话字符串中删除任何空格或()。有关详细信息,请参阅Python 2.6 doc on str.translate

在Python 3.x中,str.translate()采用映射(而不是如上所示的两个字符串)。因此,相应的片段类似于以下内容,使用str.maketrans()来生成映射 '(self.phone).translate(str.maketrans('','', '()-/ '))
有关详细信息,请参阅Python 3.1 doc on str.translate

答案 2 :(得分:1)

如何使用正则表达式?

示例:

>>> import re
>>> num = '0(532) 222 22 22'
>>> re.sub('[\D]', '', num) # Match all non-digits ([\D]), replace them with empty string, where found in the `num` variable.
'05322222222'

ChristopheD提出的建议会很好,但效率不高。

以下是使用dis模块演示此示例的测试程序(有关详细信息,请参阅模块here上的Doug Hellman的PyMOTW)。

TEST_PHONE_NUM = '0(532) 222 22 22'

def replace_method():
    print (TEST_PHONE_NUM).replace(" ","").replace("(","").replace(")","")

def list_comp_is_digit_method():
    print ''.join([x for x in TEST_PHONE_NUM if x.isdigit()])

def translate_method():
    print (TEST_PHONE_NUM).translate(None,' ()')

import re
def regex_method():
    print re.sub('[\D]', '', TEST_PHONE_NUM)

if __name__ == '__main__':
    from dis import dis

    print 'replace_method:'
    dis(replace_method)
    print
    print

    print 'list_comp_is_digit_method:'
    dis(list_comp_is_digit_method)

    print
    print

    print 'translate_method:'
    dis(translate_method)

    print
    print
    print "regex_method:"
    dis(phone_digit_strip_regex)
    print

输出:

replace_method:
  5       0 LOAD_GLOBAL              0 (TEST_PHONE_NUM)
          3 LOAD_ATTR                1 (replace)
          6 LOAD_CONST               1 (' ')
          9 LOAD_CONST               2 ('')
         12 CALL_FUNCTION            2
         15 LOAD_ATTR                1 (replace)
         18 LOAD_CONST               3 ('(')
         21 LOAD_CONST               2 ('')
         24 CALL_FUNCTION            2
         27 LOAD_ATTR                1 (replace)
         30 LOAD_CONST               4 (')')
         33 LOAD_CONST               2 ('')
         36 CALL_FUNCTION            2
         39 PRINT_ITEM          
         40 PRINT_NEWLINE       
         41 LOAD_CONST               0 (None)
         44 RETURN_VALUE   

phone_digit_strip_list_comp:
  3           0 LOAD_CONST               1 ('0(532) 222 22 22')
              3 STORE_FAST               0 (phone)

  4           6 LOAD_CONST               2 ('')
              9 LOAD_ATTR                0 (join)
             12 BUILD_LIST               0
             15 DUP_TOP             
             16 STORE_FAST               1 (_[1])
             19 LOAD_GLOBAL              1 (test_phone_num)
             22 GET_ITER            
             23 FOR_ITER                30 (to 56)
             26 STORE_FAST               2 (x)
             29 LOAD_FAST                2 (x)
             32 LOAD_ATTR                2 (isdigit)
             35 CALL_FUNCTION            0
             38 JUMP_IF_FALSE           11 (to 52)
             41 POP_TOP             
             42 LOAD_FAST                1 (_[1])
             45 LOAD_FAST                2 (x)
             48 LIST_APPEND         
             49 JUMP_ABSOLUTE           23
             52 POP_TOP             
             53 JUMP_ABSOLUTE           23
             56 DELETE_FAST              1 (_[1])
             59 CALL_FUNCTION            1
             62 PRINT_ITEM          
             63 PRINT_NEWLINE       
             64 LOAD_CONST               0 (None)
             67 RETURN_VALUE   

translate_method:
  11           0 LOAD_GLOBAL              0 (TEST_PHONE_NUM)
               3 LOAD_ATTR                1 (translate)
               6 LOAD_CONST               0 (None)
               9 LOAD_CONST               1 (' ()')
              12 CALL_FUNCTION            2
              15 PRINT_ITEM          
              16 PRINT_NEWLINE       
              17 LOAD_CONST               0 (None)
              20 RETURN_VALUE      

phone_digit_strip_regex:
  8       0 LOAD_CONST               1 ('0(532) 222 22 22')
          3 STORE_FAST               0 (phone)

  9       6 LOAD_GLOBAL              0 (re)
          9 LOAD_ATTR                1 (sub)
         12 LOAD_CONST               2 ('[\\D]')
         15 LOAD_CONST               3 ('')
         18 LOAD_GLOBAL              2 (test_phone_num)
         21 CALL_FUNCTION            3
         24 PRINT_ITEM          
         25 PRINT_NEWLINE       
         26 LOAD_CONST               0 (None)
         29 RETURN_VALUE        

翻译方法将是最有效的,但依赖于py2.6 +。正则表达式的效率略低,但更兼容(我认为对你有要求)。原始替换方法将为每次替换添加6个附加指令,而所有其他指令将保持不变。

在旁注中,将您的电话号码存储为字符串以处理前导零,并在需要时使用电话格式化程序。相信我,以前咬过我。

答案 3 :(得分:-1)

SilentGhost:dis.dis 演示了潜在的概念/执行复杂性。毕竟,OP抱怨原来的替代链太“笨拙”,不太“慢”。

我建议不要使用不可避免的正则表达式;他们只是增加概念开销和速度惩罚。使用translate()这里是恕我直言,这是一个错误的工具,并没有像原始替代链那样在概念上简单和通用。

所以你说tamaytoes,我说tomahtoes:原始解决方案在清晰度和通用性方面非常好。它根本不笨拙。为了使其更加密集​​和更具参数化,请考虑将其更改为

phone_nr_translations = [ 
    ( ' ', '', ), 
    ( '(', '', ), 
    ( ')', '', ), ]

def sanitize_phone_nr( phone_nr ):
  R = phone_nr
  for probe, replacement in phone_nr_translations:
    R = R.replace( probe, replacement )
  return R

在这个特殊的应用程序中,当然,你真正想做的只是取消任何不需要的字符,所以你可以简化这个:

probes = ' ()'

def sanitize_phone_nr( phone_nr ):
  R = phone_nr
  for probe in probes:
    R = R.replace( probe, '' )
  return R

想到它,我不太清楚你为什么要把手机nr变成一个整数 - 这只是错误的数据类型。这可以通过以下事实来证明:至少在移动网络中,+#可能更多是拨号字符串中的有效字符(dial,string-see?)。

但除此之外,清理用户输入手机nr以获得规范化和安全的表示是一个非常非常有效的问题 - 只是我觉得你的方法太具体了。为什么不将消毒方法重新编写成非常通用的东西而不会变得更复杂?毕竟,如何确保您的用户永远不会在该Web表单字段中输入其他异常字符?

所以你想要的实际上不是 dis - 允许特定字符(在unicode 5.1中有大约十万个定义的代码点,那么如何赶上这些?),但是对于允许那些在拨号字符串中被认为合法的字符。你可以用正则表达式做到这一点......

from re import compile as _new_regex
illegal_phone_nr_chrs_re = _new_regex( r"[^0-9#+]" )

def sanitize_phone_nr( phone_nr ):
  return illegal_phone_nr_chrs_re.sub( '', phone_nr )

...或有一套:

legal_phone_nr_chrs = set( '0123456789#+' )

def sanitize_phone_nr( phone_nr ):
    return ''.join( 
        chr for chr in phone_nr 
            if chr in legal_phone_nr_chrs )

最后一节可以写在一行上。这个解决方案的缺点是你可以迭代Python中的输入字符,而不是使用str.replace()或者正则表达式提供的潜在的调速器C遍历。但是,性能在任何情况下都取决于预期的使用模式(我确定你首先截断你的手机,对吧?那么那些将要处理的是很多小字符串,而不是很少的大字符串。)

请注意以下几点:我力求清晰,这就是为什么我试图避免过度使用缩写。 chrcharacternrnumber,返回值为R(更有可能是,{,1}}标准库)在我的风格书中。编程是关于理解和完成事情,而不是编写程序员编写接近gzip空间效率的代码。现在看,最后的解决方案确实完成了OP设法完成的工作(以及更多),... ...

retval

......如果需要两行代码,而OP的代码......

legal_phone_nr_chrs = set( '0123456789#+' )
def sanitize_phone_nr( phone_nr ): return ''.join( chr for chr in phone_nr if chr in legal_phone_nr_chrs )

......几乎不能压缩到四行以下。看看严格的OOP解决方案给你带来了哪些额外的包袱?我相信它大部分时间都可以被排除在外。