字符串format方法
Python2.6 开始,新增了一种格式化字符串的函数 str.format(),它增强了字符串格式化的功能。
基本语法是通过 {} 和 : 来代替以前的 % 。
“映射”示例
1. 通过位置
In [1]: '{0},{1}'.format('kzc',18)
Out[1]: 'kzc,18'
In [2]: '{},{}'.format('kzc',18)
Out[2]: 'kzc,18'
In [3]: '{1},{0},{1}'.format('kzc',18)
Out[3]: '18,kzc,18'
2. 通过关键字参数
字符串的format函数可以接受不限个参数,位置可以不按顺序,可以不用或者用多次,不过2.6不能为空{},2.7才可以
In [5]: '{name},{age}'.format(age=18,name='kzc')
Out[5]: 'kzc,18'
3. 通过对象属性
class Person:
def __init__(self,name,age):
self.name,self.age = name,age
def __str__(self):
return 'This guy is {self.name},is {self.age} old'.format(self=self)
In [2]: str(Person('kzc',18))
Out[2]: 'This guy is kzc,is 18 old'
4. 通过下标
In [7]: p=['kzc',18]
In [8]: '{0[0]},{0[1]}'.format(p)
Out[8]: 'kzc,18'
格式限定符
1. 填充与对齐
填充常跟对齐一起使用^、<、>
分别是居中、左对齐、右对齐,后面带宽度;
:
号后面带填充的字符,只能是一个字符,不指定的话默认是用空格填充
In [15]: '{:>8}'.format('189')
Out[15]: ' 189'
In [16]: '{:0>8}'.format('189')
Out[16]: '00000189'
In [17]: '{:a>8}'.format('189')
Out[17]: 'aaaaa189'
2. 精度与类型f
精度常跟类型f一起使用
In [44]: '{:.2f}'.format(321.33345)
Out[44]: '321.33'
其中.2表示长度为2的精度,f表示float类型
3. 其他类型
主要就是进制了,b、d、o、x分别是二进制、十进制、八进制、十六进制
In [54]: '{:b}'.format(17)
Out[54]: '10001'
In [55]: '{:d}'.format(17)
Out[55]: '17'
In [56]: '{:o}'.format(17)
Out[56]: '21'
In [57]: '{:x}'.format(17)
Out[57]: '11'
用,
号还能用来做金额的千位分隔符
In [47]: '{:,}'.format(1234567890)
Out[47]: '1,234,567,890'
实际用例
s = '1.2.3.4'
['{}'.format(int(i)) for i in s.split('.')]
Out[34]: ['1', '2', '3', '4']
['{:b}'.format(int(i)) for i in s.split('.')]
Out[35]: ['1', '10', '11', '100']
['{:8b}'.format(int(i)) for i in s.split('.')]
Out[36]: [' 1', ' 10', ' 11', ' 100']
['{:08b}'.format(int(i)) for i in s.split('.')]
Out[37]: ['00000001', '00000010', '00000011', '00000100']
IP地址处理相关问题
1. int32->IPv4 即点分十进制的实现
本题就是给一个Int32的地址,最后划归成对应的IPv4点分十进制的格式:
Examples
2149583361 ==> "128.32.10.1"
32 ==> "0.0.0.32"
0 ==> "0.0.0.0"
那么这个题目如果按照IPv4的定义去做就需要实现一个除2去幂的计算,也就是“点分十进制”的实现算法:
def int32_to_ip(int32):
"""
standard format: 10000000.00100000.00001010.00000001
2**31 + 2**30 + 2**29 + ...... + 2**0
"""
ip = ''
for i in range(32)[::-1]:
if int32 >= 2 ** i:
ip += '1'
int32 -= 2 ** i
else:
ip += '0'
# After this step, the format of ip is: 10000000001000000000101000000001
# Then try to separate it with '.' and convert it to
ip = ".".join([str(int(ip[i:i + 8], 2)) for i in range(0, len(ip), 8)])
return ip
如果使用Python3,那么就可以利用format的特性:
def int32_to_ip(int32):
return '{}.{}.{}.{}'.format(*int32.to_bytes(4, 'big'))
ipaddress库解法
from ipaddress import IPv4Address
def int32_to_ip(int32):
return str(IPv4Address(int32))
2. int32<->IPv4
这个题目就是实现Int32和IPv4点分十进制的格式的相互转化:
For s = "10.0.3.193", the output should be "167773121".
For s = "167969729", the output should be "10.3.3.193".
IPv4 -> int32
在这里是最体现语法糖的地方,利用了python的三元运算符、列表推导式、字符串format方法等技巧,整体过程的算法描述如下:
- 根据
.
对IPv4进行拆分 - 将拆分后的每一段数字是否在0-256之间
- 如果在转换成8位标准的二进制字符串
- 拼接4段8位二进制字符串,转换成10进制数字,再将数字转换成字符串返回
精简一下,最核心是IPv4点分十进制->32位二进制数字
的过程:
s = '1.1.1.1'
"".join(["{:0>08b}".format(int(i)) for i in s.split('.')])
Out[8]: '00000001000000010000000100000001'
IPv4 <- int32
这里和第一题一样,但是这里不用去实现点分十进制的过程了,给出一个精简的计算:
ip_str = bin(int(s)).replace('0b', '')
ip_str = (32 - len(ip_str)) * '0' + ip_str
return ".".join([str(int(ip_str[i:i + 8], 2)) for i in range(0, len(ip_str), 8)])
3. 计算两个IPv4地址之前的数量
题目很简单,就是标题的内容,下面给几个例子:
Examples
ipsBetween("10.0.0.0", "10.0.0.50") => 50
ipsBetween("10.0.0.0", "10.0.1.0") => 256
ipsBetween("20.0.0.10", "20.0.1.0") => 246
那么通过1、2两题的方式,我们就可以直接将IPv4格式变成2进制或者10进制进行减法:
def ips_between(start, end):
return ipToNumber(end) - ipToNumber(start)
def ipToNumber(p1):
rets = ''
for t in p1.split('.'):
rets += '{0:08b}'.format(int(t))
return int(rets,2)
ipaddress库解法
from ipaddress import ip_address
def ips_between(start, end):
return int(ip_address(end)) - int(ip_address(start))
4. 获取一个CIDR地址的所有IP
Examples:
Input = 192.168.1.0/31
Output = ['192.168.1.0, 192.168.1.1']
For a subnet that is not appear to be an IPv4 or IPv6 network generate exception:
Input = 213.256.46.160/28
Output = "not appear to be an IPv4 or IPv6 network"
import ipaddress
def ipsubnet2list(subnet):
ip_split_list = ['{:0>08b}'.format(int(i)) if 0 <= int(i) < 256 else False for i in subnet.split('/')[0].split('.')]
if False in ip_split_list:
return "not appear to be an IPv4 or IPv6 network"
return ", ".join([str(i) for i in list(ipaddress.ip_network(subnet).hosts())])