首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python内置数据结构之字符串

Python内置数据结构之字符串

作者头像
1846122963
发布2018-03-09 16:56:15
1.5K0
发布2018-03-09 16:56:15
举报

字符串 今天跟大家来说一说Python中的字符串数据结构。

上文回顾

让我们回顾一下可变类型及不可变类型:

  • 不可变数据类型:strinttuple
  • 可变数据类型:dictlist

今天讲解的字符串属于不可变类型。

Python字符串编码

Python3中的字符串是Unicode的序列,也就是说,Python3的字符串支持多语言了;Python2中的字符串是byte序列。

例如:

In[1]: print('含有中文的字符串str')
含有中文的字符串str

对于单个字符的编码,Python提供了ord()内置函数来获取字符的整数表示;chr()内置函数则把编码转换为对应的字符。例如:

In[2]: ord('A')
Out[2]: 65

In[3]: ord('中')
Out[3]: 20013

In[4]: chr(97)
Out[4]: 'a'

In[5]: chr(25991)
Out[5]: '文'

如果要知道字符的整数编码,那么还可以用其十六进制的形式这么写:

In[6]: '\u4e2d\u6587'
Out[6]: '中文'

Python的字符编码就介绍到这里。接下来介绍Python字符串的常用方法,看看字符串在日常当中是怎么用的。

字符串常用方法

字符串常用方法:

  1. 字符串连接:join
  2. 字符串分割:splitrsplitsplitlinespartitionrpartition
  3. 字符串修改-大小写:capitalizetitlelowerupperswapcase
  4. 字符串修改-填充或清除:centerljustrjustzfillstriprstriplstrip
  5. 字符串查找替换:countfindrfindindexrindexreplace

字符串连接(join)

join允许我们使用特定的字符来连接字符串。直接看例子吧:

In[7]: lst = ['i', 'am', 'lavenliu']

In[8]: ' '.join(lst)
Out[8]: 'i am lavenliu'

join是字符串方法,参数是内容为字符串的可迭代对象,接收者(在这里为空格)作为连接符。使用逗号进行连接:

In[9]: ','.join(lst)
Out[9]: 'i,am,lavenliu'

除了join外,我们还可以使用+进行两个字符串的连接:

In[10]: 'my' + ' name'
Out[10]: 'my name'

字符串分割(split系列方法)

# split
>>> s = 'my name is lavenliu'
>>> s
'my name is lavenliu'
>>> s.split()
['my', 'name', 'is', 'lavenliu']
>>> s.split(maxsplit=1) # maxsplit参数表示分割多少次;默认值为-1,表示分割所有分隔符
>>> s.split('ls')
['my name is lavenliu']
>>> s.split('is')
['my name ', ' lavenliu']
>>> s.split(' ', 1)
['my', 'name is lavenliu']
s.split('is')   # 以“is”为分隔符
s.split(' ', 1) # 以空格为分隔符,从左到右分隔一次
s.split(' ', 2) # 以空格为分隔符,从左到右分隔两次
s.split(' ', -1) # -1就是默认值,直到字符串分隔完成
['my', 'name', 'is', 'lavenliu']

# rsplit方法
s.rsplit()
['my', 'name', 'is', 'lavenliu']

s.rsplit(' ')
['my', 'name', 'is', 'lavenliu']

s.rsplit(' ', 1) # 与s.split(' ', 1)的分隔形式相反
['my name is', 'lavenliu']

我们看一看split函数的原型该怎么写:

def split(s, sep, maxsplit):
    ret = []
    tmp = []
    i = 0
    for c in s:
        if c != sep:
            tmp.append(c)
        else:
            i += 1
            ret.append(''.join(tmp))
            tmp.clear()
        if maxsplit > 0 and i >= maxsplit:
            return ret
    return ret

rsplit方法的原型为:

def rsplit(s, sep, maxsplit):
    ret = []
    tmp = []
    for c in reversed(s):
        if c != sep:
            tmp.append(c)
        else:
            i += 1
            ret.append(''.join(reversed(tmp)))
            tmp.clear()
        if maxsplit > 0 and i >= maxsplit:
            ret.append()
            return reversed(ret)
    return reversed(ret)

splitlines方法:

In[12]: s = '''i am lavenliu
    ...: i love python'''

In[13]: print(s.splitlines())     # 按行分割,并且返回结果不带换行符
['i am lavenliu', 'i love python']

In[14]: print(s.splitlines(True)) # 按行分割,并且返回结果带换行符
['i am lavenliu\n', 'i love python']

partition方法:

In[15]: s = 'i am lavenliu'

In[16]: s.partition(' ')
Out[16]: ('i', ' ', 'am lavenliu')

partition总是返回一个三元组,它按传入的分隔符分割一次,得到head,tail,返回结果是head,sep,tail。rpartition是partition从右往左的版本。再看一个partition的例子,

In[17]: cfg = 'mysql.connect = mysql://user:password@127.0.0.1:3306/test'

In[18]: print(cfg.partition('='))
('mysql.connect ', '=', ' mysql://user:password@127.0.0.1:3306/test')

In[19]: cfg = 'env = PATH=/usr/bin:$PATH'

In[20]: print(cfg.partition('='))
('env ', '=', ' PATH=/usr/bin:$PATH')

In[21]: print(''.partition('='))
('', '', '')

In[22]: print('='.partition('='))
('', '=', '')

partition方法实现:

def partition(s, sep):
    if s == '':
        return '', '', ''
    tmp = s.split(sep, maxsplit=1)
    if len(tmp) == 2:
        return tmp[0], sep, tmp[1]
    if len(tmp) == 1:
        return tmp[0], sep, ''

字符串大小写转换:

In[23]: s = 'my name is laven'

In[24]: print(s.capitalize())
My name is laven

In[25]: print(s.title())
My Name Is Laven

In[26]: print(s.lower())
my name is laven

In[27]: print(s.upper())
MY NAME IS LAVEN

In[28]: print(s.upper().lower())
my name is laven

In[29]: print('Hello World'.casefold()) # 不同的平台有不同的表现形式,但在同一平台下,表现形式相同,通常用来忽略大小写时的比较。
hello world

In[30]: print('Hello World'.swapcase())
hELLO wORLD

In[31]: print('\t'.expandtabs(4))
     # 此处前面有四个空格

大小写转化通常用在做比较的时候,当我们需要忽略大小写的时候,通常统一转化为全部大写或全部小写再做比较。

字符串修改之填充:

s = 'my name is laven'
help(s.center) # 默认空格填充。如果宽度小于等于原串长度,不做任何操作。
s.center(80)
>>> s.center(80)
'                                my name is laven                                '

>>> s.center(80, '#')
'################################my name is laven################################'
>>>

# ljust方法
>>> s.ljust(80)
'my name is laven                                                                '
>>>
>>> s.ljust(80, '*') # 字符串左对齐
'my name is laven****************************************************************'
>>>

# rjust方法
>>> s.rjust(80)
'

>>> s.rjust(80, '*')
'****************************************************************my name is laven'
# ljust,rjust方法是针对字符串的显示位置的

# zfill方法
>>> s.zfill(80)
'0000000000000000000000000000000000000000000000000000000000000000my name is laven'
>>>

接下来演示3个非常重的字符串方法:strip、lstrip、rstrip:

s = '   hahe hehe   \n \t'
s.strip()
>>> s.strip() # strip只能去掉字符串两边的空白或指定字符
'haha hehe'

# lstrip默认去掉前置的空白
>>> s.lstrip()
'haha hehe  \n \t'

# rstrip默认去掉后置的空白
>>> s.rstrip()
'    haha hehe'

# 去掉指定字符
>>> s = '##test##'
>>> s.strip('#')
'test'
>>> s.strip('*')
'##test##'

>>> s = '## test ##'
>>> s
'## test ##'
>>> s.strip('#')
' test '
>>> s.strip('#').strip()
'test'

strip方法可以移除指定的字符。大家可以试试看。

startswith与endswith方法,判断字符串是否以某个前缀开始,返回结果是boolean。

s = '**test##'
>>> s.startswith('*')
True
>>> s.endswith('#')
True
>>> s.endswith('test')
False
>>> s.endswith('test', 0, 5) # start,end 参数表示的是从索引start处开始到end处结束,但不包含end
False
>>> s.endswith('test', 0, 6)
True

字符查找与替换:

  • count
  • find
  • rfind
  • index
  • replace
# count方法
s = '**test##'
>>> s.count('*')
2
>>> s.count('#')
2
>>> s.find('t') # find从左向右查找
2
>>>
>>> s.find('t')
2
>>> s.find('test')
2
>>> s.rfind('test') # rfind是find的从右向左查找的版本
2
>>> s.rfind('t')
5

s = 'i very very love python'
s.find('very') # 2
s.find('very', 3) # start参数指定从哪里开始查找
s.find('very', 3, 10) # end参数指定到哪里结束查找,end不包含
s.rfind('very') # 从右往左查找,但得到的索引是从左到右

# index方法,index一个不存在的字符或子串时,会报错;而find则不会报错;
>>> s.index('t')
2
>>> s.index('test')
2
>>> s.rfind('t')
5
>>> s.find('a')
-1
>>> s.index('a')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: substring not found
s.find('a') # 使用find找一个不存在的字符,返回-1
s.index('a') # 使用index找一个不存在的字符,会抛出异常

# replace方法,可选的count,指定替换多少次
s = 'abc123abc123'
s.replace('abc', 'xyz') # 默认是全部替换,-1省略了
s.replace('abc', 'xyz', 1) # 只替换一次
s.replace('xxxx', '') # 如果要替换的字符不存在,什么都不做
s.replace('abc', 'xyz', -1) # -1表示全部替换

如果对find不是很理解,可以借助enumerate方法来查看,

In[32]: s = 'i very very love python'

In[33]: print(list(enumerate(s)))
[(0, 'i'), (1, ' '), (2, 'v'), (3, 'e'), (4, 'r'), (5, 'y'), (6, ' '), (7, 'v'), (8, 'e'), (9, 'r'), (10, 'y'), (11, ' '), (12, 'l'), (13, 'o'), (14, 'v'), (15, 'e'), (16, ' '), (17, 'p'), (18, 'y'), (19, 't'), (20, 'h'), (21, 'o'), (22, 'n')]

字符串判断函数是一些is开头的方法,这些方法用的不多。

一个比较有用的小技巧,

In[34]: line = 'url://http://lavenliu.cn'

In[35]: line.split(':', 1)
Out[35]: ['url', '//http://lavenliu.cn']

In[36]: key, value = line.split(':', 1)

In[37]: key
Out[37]: 'url'

In[38]: value
Out[38]: '//http://lavenliu.cn

splitlines方法:

In[39]: text = '''I am laven
    ...: I am a man
    ...: I like Emacs'''

In[40]: text.splitlines()
Out[40]: ['I am laven', 'I am a man', 'I like Emacs']

In[41]: text.splitlines(True) # 保留换行符
Out[41]: ['I am laven\n', 'I am a man\n', 'I like Emacs']

partition方法,

In[42]: s = 'my name is laven'

In[43]: s.partition(' ') # 类似于s.split(' ', 1)
Out[43]: ('my', ' ', 'name is laven')

In[44]: # 上面的line = 'url:http://magedu.com'可以写成如下的形式

In[45]: line.partition(':')
Out[45]: ('url', ':', '//http://lavenliu.cn')

In[46]: key, _, value = line.partition(':')

In[47]: key
Out[47]: 'url'

In[48]: value
Out[48]: '//http://lavenliu.cn'

In[49]: s.rpartition(' ')
Out[49]: ('my name is', ' ', 'laven')

字符串解包操作,

In[50]: s = 'my name is lavenliu'

In[51]: a, b, *mid, tail = s

In[52]: a
Out[52]: 'm'

In[53]: b
Out[53]: 'y'

In[54]: mid
Out[54]: 
[' ',
 'n',
 'a',
 'm',
 'e',
 ' ',
 'i',
 's',
 ' ',
 'l',
 'a',
 'v',
 'e',
 'n',
 'l',
 'i']

In[55]: tail
Out[55]: 'u'

字符串的迭代

字符串是也是可迭代的对象:

In[56]: s = 'hello world'

In[57]: for i in s:
    ...:     print(i)
    ...:     
h
e
l
l
o
 
w
o
r
l
d

In[58]:

切片及索引

In[1]: s = "use python do something"

In[2]: s[1], s[-1], s[1:6:2], s[1:], s[:-1], s[:]
Out[2]: 
('s',
 'g',
 's y',
 'se python do something',
 'use python do somethin',
 'use python do something')

In[3]: s[1:] # 从1开始到最后
Out[3]: 'se python do something'

In[4]: # 倒序
In[5]: s[::-1]
Out[5]: 'gnihtemos od nohtyp esu'

In[7]: s[4]
Out[7]: 'p'

字符串格式化

字符串格式化是拼接字符的一种手段。如:

In[8]: print(' '.join(['i', 'love', 'python']))
i love python

In[9]: print('i' + ' love ' + 'python')
i love python

join+拼接字符串难以控制格式。接下来介绍两种字符串格式化的方法。一种是printf-style方式一种是format方式。

printf风格的格式化

首先介绍一下print函数的占位符及其说明,后面的讲解会用得到。

占位符

说明

i

有符号整数数

d

有符号整数

o

有符号的八进制数

x

十六进制(以小写显示)

X

十六进制(以大写显示)

e

科学计数法(以小写显示)

E

科学计数法(以大写显示)

f

浮点数

F

浮点数

语法为:

template % tuple
>>> 'I am %s' % ('lavenliu',) # 如果只有一个元素的时候,可以不用元组;即这里可以省略逗号,或直接省略小括号。
'I am lavenliu'

template % dict
>>> 'I am %(name)s' % {'name': 'lavenliu'}
'I am lavenliu'
>>>
>>> 'I am %(name)s, my name is %(name)s' % {'name': 'lavenliu'}
'I am lavenliu, my name is lavenliu'
# 使用字典的形式的场景
## 1. 反复出现
## 2. 需要格式化内容很多

一个简单的例子,

>>> a = "this is %s %s" % ("my", 'apple')
>>> print(a)
this is my apple

占位符的演示,

>>> '%i' % 18
'18'
>>> '%d' % 18
'18'
>>> '%ld' % 18 # 为了与C语言的兼容
'18'
>>> '%o' % 18
'22'
>>> '%X' % 12
'C'
>>> '%x' % 12
'c'
>>> '%e' % 0.00000345
'3.450000e-06'
>>> '%E' % 0.00000345
'3.450000E-06'
>>> '%e' % 12
'1.200000e+01'
>>> '%f' % 0.00000345 # 默认显示6位,不足就补0,多了就舍去
'0.000003'
# 如果只显示3位小数呢
'%0.3f' % 0.00123
'0.001'
>>> '%F' % 0.00000345
'0.000003'
# r与s的区别
class A:
    def __str__(self):
        return 'I am A.__str__'


    def __repr__(self):
        return 'I am A.__repr__'


a = A()
>>> a = A()
>>> '%s' % 123
'123'
>>> '%s' % a
'I am A.__str__'
>>> '%r' % a
'I am A.__repr__'
>>> '%a' % '\n'
"'\\n'"
# str是给人看的,repr是个机器看的

# a的演示
In[11]: '%a' % '\n'
Out[11]: "'\\n'"

In[10]: '%a' % '大川淘气'
Out[10]: "'\\u5927\\u5ddd\\u6dd8\\u6c14'"

当类型不匹配时,会抛出TypeError。当占位符是%s时,其实隐式调用了str()。

format风格的字符串格式化

format语法,使用大括号作为占位符。当调用format方法时,format传入的参数会替换大括号。format方法的参数个数是可变的。

'I am {}'.format('lavenliu')
'I am {}, my age is {}'.format('lavenliu', 23) # 按照顺序
# 如果按照顺序呢
# 可以在占位符里加数字指定format参数的位置
'I am {1}, my age is {0}'.format('18, 'lavenliu'')

# 可以在占位符里加标识符,以使用关键字参数
'I am {name}, my age is {age}'.format(name='lavenliu', age=18)
# 多次出现也是可以的
'I am {name}, my name is {name}'.format('lavenliu')
'I am {0}, my name is {0}'.format('lavenliu')

# 几个好玩的用法
## 要么全是位置与关键字的
## 要么全是顺序与关键字的
## 位置的要在关键字之前
>>> '{1} {0} {name}'.format(1, 2, name='abc')
'2 1 abc'
>>> '{} {} {name}'.format(1, 2, name='abc')
'1 2 abc'

>>> '{0} {name} {1}'.format(1, 2, name='abc')
'1 abc 2'

>>> '{name} {} {}'.format(1, 2, name='abc')
'abc 1 2'

>>> '{} {name} {}'.format(1, 2, name='abc')
'1 abc 2'

# 这样写就会出错
## 顺序的,位置的,关键字的,不要混用
>>> '{} {1} {name}'.format(1, 2, name='abc')
ValueError: cannot switch from automatic field numbering to manual field specification

# 位置参数要在关键字参数之前
>>> '{} {name} {}'.format(1, name='abc', 2)
  File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument

几个format的小例子,

In[12]: b = "this is {} {}" .format("my", "apple")

In[13]: print(b)
this is my apple

In[14]: ## {}里可以加入参数的位置

In[15]: b = "this is {1} {0}" .format("apple", "my")

In[16]: print(b)
this is my apple

In[17]: ## 更加高级的用法,这里不用指定数字,因为有可能算错位置

In[18]: b = "this is {whose} {fruit}" .format(fruit="apple", whose="my")

In[19]: print(b)
this is my apple

还可以使用类进行格式化,很吊的,

class A:
    def __init__(self):
        self.x = 1
        self.y = 2


>>> a = A()
>>> a.x
1
>>> a.y
2

>>> '{0.x} {0.y}'.format(a)
'1 2'

>>> '{instance.x}'.format(instance=a)
'1'

可以使用列表进行格式化,

>>> lst = [1, 2, 3]
>>> '{0[0]}'.format(lst)
'1'
>>> '{lst[0]}'.format(lst=lst)
'1'

再来看几个例子,主要涉及格式化时的对齐操作,

# < 左对齐
>>> '{0:<80}'.format('lavenliu')
'lavenliu                                                                          '

# > 右对齐
>>> '{0:>80}'.format('lavenliu')

# ^ 居中对齐
'{0:^80}'.format('lavenliu')

# 默认的,字符串对齐方式是左对齐
'{0:80}'.format('lavenliu')

# 默认的,数字对齐方式是右对齐
'{0:80}'.format(10)

# 数字
'{0:d}'.format(10)
'{:n}'.format(1000)
'{:b}'.format(10)

# 还可以嵌套
>>> '{0:^{width}}'.format('lavenliu', width=80)
'                                     lavenliu                                     '

>>> '{0:#^{width}}'.format('lavenliu', width=80)
'#####################################lavenliu#####################################'

>>> '{0:{fill}^{width}}'.format('lavenliu', width=80, fill='*')
'*************************************lavenliu*************************************'

printf-style格式化对于从其他语言,尤其是C语言转过来的,非常容易接受,但是Python并不推荐这种方法。 尽量使用内置的这种format的方式来格式化字符串。

另外,也可以使用字典的方式实现字符串的格式化。

In[20]: a = "this is %(whose)s %(fruit)s" % {'whose': 'my', 'fruit': 'apple'}

In[21]: a
Out[21]: 'this is my apple'

今日总结

  1. 字符串是不可变的数据类型;
  2. 字符串可以进行索引、切片、迭代等操作;
  3. 字符串内置了很多方法供我们使用;
  4. Python3中的字符默认是Unicode格式的;

格式化总结

  1. 占位符与参数不匹配,会抛出异常
  2. {} 按照顺序,使用位置参数
  3. {数字 i} 会把位置参数当成一个列表 args,args[i] 当i不是args的索引的时候,抛出IndexError
  4. {关键字 k} 会把关键字参数当成一个字典kwargs,使用kwargs[k] 当k不是kwargs的key时,会抛出KeyError
  5. 如果要单纯的打印大括号,可以使用{{}};如果要打印形如{18}的形式,可以使用{{{}}}
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-08-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小白的技术客栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 上文回顾
  • Python字符串编码
  • 字符串常用方法
    • 字符串连接(join)
      • 字符串分割(split系列方法)
        • 字符串的迭代
        • 切片及索引
        • 字符串格式化
          • printf风格的格式化
            • format风格的字符串格式化
            • 今日总结
              • 格式化总结
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档