精华内容
下载资源
问答
  • 正如《你真的知道Python的字符串是什么吗?》所写,Python 字符串是由 Uniocde 编码的字符组成的不可变序列,它具备与其它序列共有的一些操作,例如判断元素是否存在、拼接序列、切片操作、求长度、求最值、求元素...

    正如《你真的知道Python的字符串是什么吗?》所写,Python 中字符串是由 Uniocde 编码的字符组成的不可变序列,它具备与其它序列共有的一些操作,例如判断元素是否存在、拼接序列、切片操作、求长度、求最值、求元素的索引位置及出现次数等等。

    除此之外,它还有很多特有的操作,值得我们时常温故学习,所以,今天我就跟大家继续聊聊字符串。

    本文主要介绍 Python 字符串特有的操作方法,比如它的拼接、拆分、替换、查找及字符判断等使用方法,辨析了一些可能的误区。最后,还做了两个扩展思考:为什么 Python 字符串不具备列表类型的某些操作呢,为什么它不具备 Java 字符串的一些操作呢?两相比较,希望能帮助你透彻地理解——Python 的字符串到底怎么用?

    0. 拼接字符串

    字符串的拼接操作最常用,我专门为这个话题写过一篇《详解Python拼接字符串的七种方式》,建议你回看。

    在此,简单回顾一下:七种拼接方式从实现原理上划分为三类,即格式化类(%占位符、format()、template)、拼接类(+操作符、类元祖方式、join())与插值类(f-string),在使用上,我有如下建议——

    当要处理字符串列表等序列结构时,采用join()方式;拼接长度不超过20时,选用+号操作符方式;长度超过20的情况,高版本选用f-string,低版本时看情况使用format()或join()方式。

    不敢说字符串就只有这七种拼接方式,但应该说它们是最常见的了。有小伙伴说,我写漏了一种,即字符串乘法 ,可以重复拼接自身。没错,从结果上看,这是第八种拼接方式,视为补充吧。

    关于字符串拼接,还得补充一个建议,即在复杂场景下,尽量避免使用以上几类原生方法,而应该使用外置的强大的处理库。比如在拼接 SQL 语句的时候,经常要根据不同的条件分支,来组装不同的查询语句,而且还得插入不同的变量值,所以当面临这种复杂的场景时,传统拼接方式只会加剧代码的复杂度、降低可读性和维护性。使用 SQLAlchemy 模块,将有效解决这个问题。

    1. 拆分字符串

    在字符串的几种拼接方法中,join() 方法可以将列表中的字符串元素,拼接成一个长的字符串,与此相反,split() 方法可以将长字符串拆分成一个列表。前面已说过,字符串是不可变序列,所以字符串拆分过程是在拷贝的字符串上进行,并不会改变原有字符串。

    split() 方法可接收两个参数,第一个参数是分隔符,即用来分隔字符串的字符,默认是所有的空字符,包括空格、换行(\n)、制表符(\t)等。拆分过程会消耗分隔符,所以拆分结果中不包含分隔符。

    s = 'Hello world'
    l = '''Hi there , my name is     Python猫
    Do you like me ?
    '''
    
    # 不传参数时,默认分隔符为所有空字符
    s.split() >>> ['Hello', 'world']
    s.split(' ') >>> ['Hello', 'world']
    s.split('  ') >>> ['Hello world'] # 不存在两个空格符
    s.split('world') >>> ['Hello', '']
    
    # 空字符包括空格、多个空格、换行符等
    l.split() >>> ['Hi', 'there', ',', 'my', 'name', 'is', 'Python猫', 'Do', 'you', 'like', 'me', '?']
    复制代码

    split() 方法的第二个参数是一个数字,默认是缺省,缺省时全分隔,也可以用 maxsplit 来指定拆分次数。

    # 按位置传参
    l.split(' ',3)
    >>> ['Hi', 'there', ',', 'my name is     Python 猫\nDo you like me ?\n']
    
    # 指定传参
    l.split(maxsplit=3)
    >>> ['Hi', 'there', ',', 'my name is     Python 猫\nDo you like me ?\n']
    
    # 错误用法
    l.split(3)
    ---------------
    TypeError  Traceback (most recent call last)
    <ipython-input-42-6c16d1a50bca> in <module>()
    ----> 1 l.split(3)
    TypeError: must be str or None, not int
    复制代码

    split() 方法是从左往右遍历,与之相对,rsplit() 方法是从右往左遍历,比较少用,但是会有奇效。

    拆分字符串还有一种方法,即 splitlines() ,这个方法会按行拆分字符串,它接收一个参数 True 或 False ,分别决定换行符是否会被保留,默认值 False ,即不保留换行符。

    # 默认不保留换行符
    'ab c\n\nde fg\rkl\r\n'.splitlines()
    >>> ['ab c', '', 'de fg', 'kl']
    
    'ab c\n\nde fg\rkl\r\n'.splitlines(True)
    >>> ['ab c\n', '\n', 'de fg\r', 'kl\r\n']
    复制代码

    2. 替换字符串

    替换字符串包括如下场景:大小写替换、特定符号替换、自定义片段替换......

    再次说明,字符串是不可变对象,以下操作并不会改变原有字符串。

     

     

     

    以上这些方法都很明了,使用也简单,建议你亲自试验一下。这里只说说 strip() 方法,它比较常用,可以去除字符串前后的空格,不仅如此,它还可以删除首末位置的指定的字符。

    s = '******Hello world******'
    s.strip('*') >>> 'Hello world'
    复制代码

    3. 查找字符串

    查找字符串中是否包含某些内容,这是挺常用的操作。Python 中有多种实现方式,例如内置的 find() 方法,但是这个方法并不常用,因为它仅仅告诉你所查找内容的索引位置,而在通常情况下,这个位置并不是我们的目的。

    find() 方法与 index() 方法的效果一样,它们的最大的区别只在于,找不到内容时的返回值不同,一个返回 -1,一个抛出异常 :

    s = 'Hello world'
    
    s.find('cat') >>>  -1
    
    s.index('cat') 
    >>> ValueError  Traceback (most recent call last)
    <ipython-input-55-442007c50b6f> in <module>()
    ----> 1 s.index('cat')
    
    ValueError: substring not found
    复制代码

    以上两个方法,只能用来满足最简单的查找需求。在实战中,我们常常要查找特定模式的内容,例如某种格式的日期字符串,这就得借助更强大的查找工具了。正则表达式和 re 模块就是这样的工具,正则表达式用来定制匹配规则,re 模块则提供了 match() 、find() 及 findall() 等方法,它们组合起来,可以实现复杂的查找功能。限于篇幅,今后再对这两大工具做详细介绍,这里有一个简单的例子:

    import re
    datepat = re.compile(r'\d+/\d+/\d+')
    text = 'Today is 11/21/2018. Tomorrow is 11/22/2018.'
    datepat.findall(text)
    >>> ['11/21/2018', '11/22/2018']
    复制代码

    4. 字符判断

    判断字符串是否(只)包含某些字符内容,这类使用场景也很常见,例如在网站注册时,要求用户名只能包含英文字母和数字,那么,当校验输入内容时,就需要判断它是否只包含这些字符。其它常用的判断操作,详列如下:

     

     

     

    5. 字符串不可以做的事

    上文内容都是 Python 字符串特有的操作方法,相信读完之后,你更清楚知道 Python 能够做什么了。

    但是,这还不足以回答本文标题的问题——你真的知道 Python 的字符串怎么用吗?这些特有的操作方法,再加上之前文章提到的序列共有的操作、字符串读写文件、字符串打印、字符串Intern机制等等内容,才差不多能够回答这个问题。

    尽管如此,为了体现严谨性,我试着再聊聊“Python 字符串不可以做的事”,从相反的维度来补充回答这个问题。下面是开拓思维,进行头脑风暴的时刻:

    (1)受限的序列

    与典型的序列类型相比,字符串不具备列表的如下操作:append()、clear()、copy()、insert()、pop()、remove(),等等。这是为什么呢?

    有几个很好理解,即append()、insert()、pop() 和 remove(),它们都是对单个元素的操作,但是,字符串中的单个元素就是单个字符,通常没有任何意义,我们也不会频繁对其做增删操作,所以,字符串没有这几个方法也算合理。

    列表的 clear() 方法会清空列表,用来节省内存空间,其效果等同于 anylist[:] = [] ,但是,奇怪的是,Python 并不支持清空/删除操作。

    首先,字符串没有 clear() 方法,其次,它是不可变对象,不支持这种赋值操作 anystr[:] = '' ,也不支持 del anystr[:] 操作:

    s = 'Hello world'
    
    s[:] = ''
    >>> 报错:TypeError: 'str' object does not support item assignment
    
    del s[:]
    >>> 报错:TypeError: 'str' object does not support item deletion
    复制代码

    当然,你也别想通过 del s 来删除字符串,因为变量名 s 只是字符串对象的引用 (挖坑,以后写写这个话题),只是一个标签,删除标签并不会直接导致对象实体的消亡。

    如此看来,想要手动清空/删除 Python 字符串,似乎是无解。

    最后还有一个 copy() 方法,这就是拷贝嘛,可是字符串也没有这个方法。为什么呢?难道拷贝字符串的场景不多么?在这点上,我也没想出个所以然来,搁置疑问。

    通过以上几个常用列表操作的比较,我们可以看出字符串这种序列是挺受限的。列表可以看成多节车厢链接成的火车,而字符串感觉就只像多个座椅联排成的长车厢,真是同源不同相啊。

    (2)比就比,谁怕谁

    接下来,又到了 Python 字符串与 Java 字符串 PK 的时刻。在上一篇文章《你真的知道Python的字符串是什么吗?》中,它们已经在对象定义的角度切磋了两回合,胜利的天平倒向了 Python,这次看看会比出个啥结果吧。

    Java 中有 比较字符串 的方法,即 compareTo() 方法与 equals() 方法,前一个方法逐一比较两个字符串的字符编码,返回一个整型的差值,后一个方法在整体上比较两个字符串的内容是否相等。

    Python 字符串没有这两个单独的方法,但要实现类似的功能却很简便。 先看例子:

    myName = "Python猫"
    cmpName = "world"
    newName = myName
    
    # 直接用比较符号进行compare
    myName > cmpName  
    >>> False
    myName == newName
    >>> True
    cmpName != newName
    >>> True
    
    # 比较是否同一对象
    myName is cmpName
    >>> False
    myName is newName
    >>> True
    复制代码

    上例中,如果把赋值的字符串换成列表或者其它对象,这些比较操作也是可以进行的。也就是说,作比较的能力 是 Python 公民们的一项基本能力,并不会因为你是字符串就给你设限,或者给你开特权。

    与此类似,Python 公民们自带求自身长度的能力 ,len() 方法是内置方法,可以直接传入任意序列参数,求解长度。Java 中则要求不同的序列对象,只能调用各自的 length() 方法。说个形象的比喻,Python 中共用一把秤,三教九流之辈都能拿它称重,而Java 中有多把秤,你称你的,我称我的,大家“井水不犯河水”。

    Python 中曾经有 cmp() 方法和 __cmp__() 魔术方法,但官方嫌弃它们鸡肋,所以在Python 3 中移除掉了。虽然在 operator 模块中还为它留下了一脉香火,但保不定哪天就会彻底废弃。

    import operator
    operator.eq('hello', 'name')
    >>> False
    operator.eq('hello', 'hello')
    >>> True
    operator.gt('hello', 'name')
    >>> False
    operator.lt('hello', 'name')
    >>> True
    复制代码

    (3)墙上的门

    在 Java 中,字符串还有一个强大的 valueOf() 方法,它可以接收多种类型的参数,如boolean、char、char数组、double、float、int等等,然后返回这些参数的字符串类型。 例如,要把 int 转为字符串,可以用 String.valueOf(anynum) 。

    Python 字符串依然没有这个单独的方法,但要实现相同的功能却很简便。对Python来说,不同的数据类型转换成字符串,那是小菜一碟,例如:

    str(123) >>> '123'
    str(True) >>> 'True'
    str(1.22) >>> '1.22'
    str([1,2]) >>> '[1, 2]'
    str({'name':'python', 'sex':'male'})
    >>> "{'name': 'python', 'sex': 'male'}"
    复制代码

    而从字符串转换为其它类型,也不难,例如,int('123') 即可由字符串'123' 得到数字 123。对比 Java,这个操作要写成 Integer.parseInt('123')

    在Java 的不同数据类型之间,那道分隔之墙矗立得很高,仿佛需要借助一座更高的吊桥才能沟通两边,而在灵活的 Python 里,你可以很方便地打开墙上的那扇门,来往穿越。

    小结一下,跟 Java 相比,Python 字符串确实没有几项方法,但是事出有因,它们的天赋能力可不弱,所有这些操作都能简明地实现。一方面,Python 字符串做不到某些事,但是另一方面,Python 可以出色地做成这些事,孰优孰劣,高下立判。

    6. 总结

    写文章贵在善始善终,现在给大家总结一下:本文主要介绍 Python 字符串特有的操作方法,比如它的拼接、拆分、替换、查找及字符判断等使用方法,从正向回答,Python 字符串能做什么?最后,我们还从反向来回答了 Python 字符串不能做什么?有些不能做,实际上是 不为,是为了在其它地方更好地作为,归根到底,应该有的功能,Python 字符串全都有了。

    本文中依然将 Python 与 Java 做了比较,有几项小小的差异,背后反映的其实是,两套语言系统在世界观上的差异。古人云,以铜为镜,可以正衣冠。那么,在编程语言的世界里,以另一种语言为镜,也更能看清这种语言的面貌。希望这种跨语言的思维碰撞,能为你擦出智慧的火花。

    最后是福利时刻:本公众号(Python猫)由清华大学出版社赞助,将抽奖送出两本新书《深入浅出Python机器学习》,截止时间到11月29日18:18,点击 这个链接,马上参与吧。

    -----------------

    本文原创并首发于微信公众号【Python猫】,后台回复“爱学习”,免费获得20+本精选电子书。

    扩展阅读:

    详解Python拼接字符串的七种方式

    你真的知道Python的字符串是什么吗?

    Java字符串比较方法:

    blog.csdn.net/barryhappy/…

    Python3为何取消cmp方法:

    www.zhihu.com/question/47…

     

    展开全文
  • 由于字符串是不可变数据类型,so自身没有增删改操作,只会返回一个新对象。切记,切记,切记!!! 字符编码encode,decode a='我好帅呀' byte=a.encode(encoding='utf8')#b'\xe6\x88\x91\xe5\xa5\xbd\xe5\xb8\...

    想要真正了解有关字符串的作用吗?那就继续往下面看下去吧
    一个方法一个代码帮你了解的明明白白,look!look! look!
    由于字符串是不可变数据类型,so自身没有增删改的操作,只会返回一个新的对象。切记,切记,切记!!!

    字符编码encode,decode

    a='我好帅呀'
    byte=a.encode(encoding='utf8')#b'\xe6\x88\x91\xe5\xa5\xbd\xe5\xb8\x85\xe5\x91\x80'
    b=byte.decode(encoding='utf8')#编码与解码的encoding必须一样
    print(b)
    

    字符串中字符的替换

    str_1='hello,python'
    str-2=str_1.replace('h','w',1)#将h->w,次数为1
    print(str_1)#输出  hello,python
    print(str_2)#输出  wello,python
    

    字符串的大小写转换

    str_1='HELLO,python'
    str_2=str_1.upper()#HELLO,PYTHON ,全为大写 
    str_3=str_1.lower()#hello,python,全为小写
    str_4=str_1.title()#Hello,Python,每个单词的首字母大写'xie
    str_5=str_1.swapcase()#hello,PYTHON,大写改为小写,小写改为大写
    str_6=str_1.capitalize()#Hello,python,只有第一个字母大写
    print(str_2,str_3,str_4,str_5,str_6)
    

    判断字符串由什么组成,所以返回 bool(true or false)

    str.isdigit()#判断字符串是否全由数字组成
    str.isalpha()#判断字符串是否由字母和中文组成
    str.isalnum()#判断字符串是否是否由字母和数字组成
    str.isspace()#判断字符串是否由  空白字符(\n,\t,\r, )    组成
    str.isidentifier()#判断字符串是否为标识符
    str.isdecimal()#判断字符串是否数字全为十进制的
    

    字符串的合并

    a=['h','e','l','l','o']
    str_1=''.join(a)#join函数的参数为列表或元组
    print(str_1)#hello
    

    字符串中的查找

    str_1='hello,hello'
    str_2='lo'
    a=str_1.index(str_2)#从左开始查找,返回索引
    b=str_1.rindex(str_2)#从右开始查找,返回索引
    print(a,b)#3,9
    str_1='hello,hello'
    str_2='lo'
    a=str_1.find(str_2)#从左开始查找,返回索引
    b=str_1.rfind(str_2)#从右开始查找,返回索引
    print(a,b)#3,9
    

    那find与index的区别呢?就是如果str_2在str_1中没有找到的话,index(rindex)方法返回ValueError: substring not found,而find(rfind)返回-1

    字符串切片

    #切片左闭右开
    str_1='bbjsdjbavhhbhbbjnnkmkj'
    str_2=str_1[:3]#0,1,2
    str_3=str_1[1:7]#1,2,3,4,5,6
    str_4=str_1[1:]#从索引1到字符串结束
    print(str_2)#bbj
    print(str_3)#bjsdjb
    print(str_4)#bjsdjbavhhbhbbjnnkmkj
    
    

    去字符串头尾的空白字符

    a='   sdsdjjj   '
    b=a.strip()#去除头尾空白字符
    c=a.lstrip()#去除左边的空白字符
    d=a.rstrip()#去除右边的空白字符
    print(b)
    print(c)
    print(d)
    

    分割存为 列表

    str_1='hello,world,python'
    str_2=str_1.split(',',1)#第一个参数为字符串中的字符,第二个参数为分割次数(默认为全分割
    str_3=str_1.split('l')
    print(str_1)#hello,world,python
    print(str_2#['hello,world,python']
    print(str_3)#['he', '', 'o,wor', 'd,python']
    

    查找字符在字符串中出现的次数

    str_1='hdijicjdsjssjdew'
    con=str_1.count('j')
    print(con)
    

    字符串之间的比较(>,=>,<,<=,==,!=)这是比较值,is比较的是id,但都返回bool

    a,b,d='adcd','abdc','adcd'
    print(a==b)#false
    print(a is d)#true
    

    字符串的对齐方式

    str_1='abcd'
    a=str_1.center(8,'*')#第一个参数表示字符长度,第二参数表示填充字符(默认填充空格)
    b=str_1.ljust(9,'@')#第一个参数表示字符长度,第二参数表示填充字符(默认填充空格)
    c=str_1.rjust(10,'%')#第一个参数表示字符长度,第二参数表示填充字符(默认填充空格)
    d=str_1.zfill(10)#参数表示字符长度,填充0
    e=str_1.rjust(10)#参数表示字符长度,没有指示填充字符,则为填充空格
    f=str_1.center(3,'*')#指定字符长度小于实际长度,则返回原字符串
    print(a)
    print(b)
    print(c)
    print(d)
    print(e)
    print(f)
    

    最后我想问个问题

    第一个问题

    a=‘123’
    b=a
    a=‘456’
    b=?

    第二个问题

    a=(‘a’,‘b’,[‘c’,‘d’])
    b=(a)
    a[2][0]=‘e’
    b=?

    第一个问题中a变了,但b没有变
    第二个问题中a变了,但b也变了,这是为什么吗?

    展开全文
  •  字符串顾名思义就是一串字符,由于Python中没有“字符”这种数据类型,所以单个的字符也依然是字符串类型的。字符串可以包含一切数据,无论是能从键盘上找到的,还是你根本都不认识的。与数一样,字符串也是值。...

        概论

      字符串顾名思义就是一串字符,由于Python中没有“字符”这种数据类型,所以单个的字符也依然是字符串类型的。字符串可以包含一切数据,无论是能从键盘上找到的,还是你根本都不认识的。与数一样,字符串也是值。字符串是不可变的类型。字符串用""双引号或者''单引号扩起,你可能会问,这有什么差别吗?其实没有任何差别。使用单双引号的输出结果完全相同。

      既然如此,为何同时支持单引号和双引号呢?因为你可能遇到如下情况:

      这里就体现出单双引号的作用,如果只使用单引号或者双引号,在执行如上其中一种情况的时候,解释器就会报错。

      除了单引号和双引号,三引号也是一个非常好用的定义方法,它的用法和三引号注释是相同的,也是可以支持将多行扩起,单引号和双引号只能定义在同一行内。

        str()方法

      字符串既是一个类型也是一个方法,str()就是一个工厂函数,它会把括号内的值转化成字符串,但是这个转化过程也不是什么都无脑转化,它遵循了字符串的一些方法。比如str()会自动识别字符串中的单引号或者双引号,以作为字符串结束的标志,而当str()找到换行符和制表符之后,也不会按照原样将它们输出。

    比如说你想让解释器输出s\nb,小牛逼,然后str()识别到"\n"就作为换行符输出了,结果就变成了傻逼。。。一般情况下把\n作为换行符代替回车键是很方便的,但是当你真的想让解释器打出'\n'的时候就要用到特殊的方法了。

        反斜杠(\)

      反斜杠是让斜杠后面的一个可以让str()启动神秘功能的特殊字符失去特殊作用,变成一般的字符。它遵循从左到右的运算顺序。比如说我在"\n"前面加上反斜杠,"\n"也就不作为换行符被str()执行换行操作了,它会变成一般字符"\n"输出。

      值得注意的是,反斜杠出现在特殊字符前面会隐形,而出现在一般字符的前面会作为普通的字符输出。

      想要输出两个\的话,因为\本身也是特殊字符,所以"\\"的前面一个反斜杠会把后面的反斜杠作为特殊符号转义成一般符号,它自己则在输出的时候隐形了,如果想要输出两个反斜杠的话,要打三个或者四个反斜杠。

      一般使用反斜杠让制表符、换行符、反斜杠自己、单双引号的魔法失灵,从而作为普通字符来输出它们。

        原始字符串

      原始字符串就是告诉计算机,一切开始简单粗暴,我输入什么,就给我输出什么,但是要注意不要以反斜杠结尾,因为反斜杠会让最后一个引号失去标记结尾的作用,导致str()无法识别结尾,以至于报错。

       字符串内置方法

    1.按索引取值

    >>> s='string'
    >>> s[0]
    's'
    >>> s[1]
    't'
    >>> s[-1]
    'g'

    -1是最后一位,索引支持从后往前取值。

    2.切片

    >>> s='string'
    >>> s[1:3]
    'tr'
    >>> s[3:1:-1]
    'ir'

    切片是顾头不顾尾的,也就是取不到结尾索引的位置。永远在结尾索引的前一位就截止了。

    切片最后一个参数是步长,可以为正也可以为负。

    3.长度len

    字符串元素的个数。

    4.成员运算in和not in

    判断一个子字符串是否存在于大字符串中

    5.移除空白strip: 用来去除字符串左右两边的字符,不指定默认去除的是空格

    >>> s='   string    '
    >>> s.strip()
    'string'
    >>> s='  ***string***    '
    >>> s.strip('*')
    '  ***string***    '
    # 当指定字符时,则不清楚空格\换行符,只清楚指定的字符。

    6.切分split:针对有规律的字符串,按照某种分隔符切成列表

    >>> s='a|b|c|d|e|f|g'
    >>> s.split('|')
    ['a', 'b', 'c', 'd', 'e', 'f', 'g']

    7.join:列表拼接成字符串

    >>> '_'.join(['a', 'b', 'c', 'd', 'e', 'f', 'g'])
    'a_b_c_d_e_f_g'

    8.lower,upper大小写转化

    >>> 'ABC'.lower()
    'abc'
    >>> 'abc'.upper()
    'ABC'

    9.startswith,endswith 判定字符串开头和结尾是否是某个子字符串

    >>> 'abcaaaaa'.startswith('abc')
    True
    >>> 'abcaaaaa'.endswith('a')
    True

    10.format的三种玩法

      1.按位传参

      2.关键字传参

      3.按索引传参

    11.replace(old,new)

    Return a copy with all occurrences of substring old replaced by new.

    12.isdigit等数字判别

    isdigit  判定一个字符串是否是纯阿拉伯数字,可判定Unicode和Bytes编码

    isdecimal 判定Unicode编码的阿拉伯数字

    isnumberic 判定中文、罗马、阿拉伯数字

    13.find 输出子字符串在字符串中第一个索引

    >>> '123456'.find('56')
    4

    14.center,ljust,rjust,zfill 填充

    15.captalize,swapcase,title

    >>> 'abcdef dddddd'.capitalize()  # 句首字母大写
    'Abcdef dddddd'
    >>> 'abcAef dddddd'.swapcase()  # 大小写反转
    'ABCaEF DDDDDD'
    >>> 'abcAef dddddd'.title()  #单词首字母大写
    'Abcaef Dddddd'

     

    转载于:https://www.cnblogs.com/forcee/p/10629568.html

    展开全文
  • 你真知道 Python 字符串怎么用吗?

    千次阅读 2018-12-30 08:58:00
    作者 |豌豆花下猫责编 | 郭芮Python 中字符串是由 Uniocde 编码的字符组成的不可变序列,它具备与其它序列共有的一些操作,例如判断元素是否存在、拼接序列、...
        

    640?wx_fmt=gif

    640?wx_fmt=jpeg

    作者 | 豌豆花下猫
    责编 | 郭芮

    Python 中字符串是由 Uniocde 编码的字符组成的不可变序列,它具备与其它序列共有的一些操作,例如判断元素是否存在、拼接序列、切片操作、求长度、求最值、求元素的索引位置及出现次数等等。

    除此之外,它还有很多特有的操作,值得我们时常温故学习,所以,今天我就跟大家继续聊聊字符串。

    本文主要介绍 Python 字符串特有的操作方法,比如它的拼接、拆分、替换、查找及字符判断等使用方法,辨析了一些可能的误区。最后,还做了两个扩展思考:为什么 Python 字符串不具备列表类型的某些操作呢,为什么它不具备 Java 字符串的一些操作呢?两相比较,希望能帮助你透彻地理解——Python 的字符串到底怎么用?


    640?wx_fmt=png

    拼接字符串


    字符串的拼接操作最常用,七种拼接方式从实现原理上划分为三类,即格式化类(%占位符、format()、template)、拼接类(+操作符、类元祖方式、join())与插值类(f-string),在使用上,我有如下建议:

    当要处理字符串列表等序列结构时,采用join()方式;

    拼接长度不超过20时,选用+号操作符方式;

    长度超过20的情况,高版本选用f-string,低版本时看情况使用format()或join()方式。

    不敢说字符串就只有这七种拼接方式,但应该说它们是最常见的了。有小伙伴说,我写漏了一种,即字符串乘法,可以重复拼接自身。没错,从结果上看,这是第八种拼接方式,视为补充吧。

    关于字符串拼接,还得补充一个建议,即在复杂场景下,尽量避免使用以上几类原生方法,而应该使用外置的强大的处理库。

    比如在拼接 SQL 语句的时候,经常要根据不同的条件分支,来组装不同的查询语句,而且还得插入不同的变量值,所以当面临这种复杂的场景时,传统拼接方式只会加剧代码的复杂度、降低可读性和维护性。使用SQLAlchemy模块,将有效解决这个问题。


    640?wx_fmt=png

    拆分字符串


    在字符串的几种拼接方法中,join() 方法可以将列表中的字符串元素,拼接成一个长的字符串,与此相反,split() 方法可以将长字符串拆分成一个列表。前面已说过,字符串是不可变序列,所以字符串拆分过程是在拷贝的字符串上进行,并不会改变原有字符串。

    split() 方法可接收两个参数,第一个参数是分隔符,即用来分隔字符串的字符,默认是所有的空字符,包括空格、换行(\n)、制表符(\t)等。拆分过程会消耗分隔符,所以拆分结果中不包含分隔符。

    s = 'Hello world'
    l = '''Hi there , my name is     Python猫
    Do you like me ?
    '''


    # 不传参数时,默认分隔符为所有空字符
    s.split() >>> ['Hello''world']
    s.split(' '>>> ['Hello''world']
    s.split('  '>>> ['Hello world'# 不存在两个空格符
    s.split('world'>>> ['Hello''']

    # 空字符包括空格、多个空格、换行符等
    l.split() >>> ['Hi''there'',''my''name''is''Python猫''Do''you''like''me''?']

    split() 方法的第二个参数是一个数字,默认是缺省,缺省时全分隔,也可以用 maxsplit 来指定拆分次数。

    # 按位置传参
    l.split(' ',3)
    >>> ['Hi''there'',''my name is     Python 猫\nDo you like me ?\n']

    # 指定传参
    l.split(maxsplit=3)
    >>> ['Hi''there'',''my name is     Python 猫\nDo you like me ?\n']

    # 错误用法
    l.split(3)
    ---------------
    TypeError  Traceback (most recent call last)
    <ipython-input-42-6c16d1a50bca> in <module>()
    ----> 1 l.split(3)
    TypeError: must be str or None, not int

    split() 方法是从左往右遍历,与之相对,rsplit() 方法是从右往左遍历,比较少用,但是会有奇效。

    拆分字符串还有一种方法,即 splitlines() ,这个方法会按行拆分字符串,它接收一个参数 True 或 False,分别决定换行符是否会被保留,默认值 False,即不保留换行符。

    # 默认不保留换行符
    'ab c\n\nde fg\rkl\r\n'.splitlines()
    >>> ['ab c''''de fg''kl']

    'ab c\n\nde fg\rkl\r\n'.splitlines(True)
    >>> ['ab c\n''\n''de fg\r''kl\r\n']


    640?wx_fmt=png

    替换字符串


    替换字符串包括如下场景:大小写替换、特定符号替换、自定义片段替换……

    再次说明,字符串是不可变对象,以下操作并不会改变原有字符串。

    640?wx_fmt=jpeg

    以上这些方法都很明了,使用也简单,建议你亲自试验一下。这里只说说 strip() 方法,它比较常用,可以去除字符串前后的空格,不仅如此,它还可以删除首末位置的指定的字符。

    s = '******Hello world******'
    s.strip('*'>>> 'Hello world'


    640?wx_fmt=png

    查找字符串


    查找字符串中是否包含某些内容,这是挺常用的操作。Python 中有多种实现方式,例如内置的 find() 方法,但是这个方法并不常用,因为它仅仅告诉你所查找内容的索引位置,而在通常情况下,这个位置并不是我们的目的。

    find() 方法与 index() 方法的效果一样,它们的最大的区别只在于,找不到内容时的返回值不同,一个返回 -1,一个抛出异常 :

    s = 'Hello world'

    s.find('cat'>>>  -1

    s.index('cat'
    >>> ValueError  Traceback (most recent call last)
    <ipython-input-55-442007c50b6f> in <module>()
    ----> 1 s.index('cat')

    ValueError: substring not found

    以上两个方法,只能用来满足最简单的查找需求。

    在实战中,我们常常要查找特定模式的内容,例如某种格式的日期字符串,这就得借助更强大的查找工具了。正则表达式和 re 模块就是这样的工具,正则表达式用来定制匹配规则,re 模块则提供了 match() 、find() 及 findall() 等方法,它们组合起来,可以实现复杂的查找功能。限于篇幅,今后再对这两大工具做详细介绍,这里有一个简单的例子:

    import re
    datepat = re.compile(r'\d+/\d+/\d+')
    text = 'Today is 11/21/2018. Tomorrow is 11/22/2018.'
    datepat.findall(text)
    >>> ['11/21/2018''11/22/2018']


    640?wx_fmt=png

    字符判断


    判断字符串是否(只)包含某些字符内容,这类使用场景也很常见,例如在网站注册时,要求用户名只能包含英文字母和数字,那么,当校验输入内容时,就需要判断它是否只包含这些字符。其它常用的判断操作,详列如下:

    640?wx_fmt=jpeg


    640?wx_fmt=png

    字符串不可以做的事


    上文内容都是 Python 字符串特有的操作方法,相信读完之后,你更清楚知道 Python 能够做什么了。

    但是,这还不足以回答本文标题的问题——你真的知道 Python 的字符串怎么用吗?这些特有的操作方法,再加上之前文章提到的序列共有的操作、字符串读写文件、字符串打印、字符串Intern机制等等内容,才差不多能够回答这个问题。

    尽管如此,为了体现严谨性,我试着再聊聊“Python 字符串不可以做的事”,从相反的维度来补充回答这个问题。下面是开拓思维,进行头脑风暴的时刻:

    (1)受限的序列

    与典型的序列类型相比,字符串不具备列表的如下操作:append()、clear()、copy()、insert()、pop()、remove(),等等。这是为什么呢?

    有几个很好理解,即append()、insert()、pop() 和 remove()都是对单个元素的操作,但是字符串中的单个元素就是单个字符,通常没有任何意义,我们也不会频繁对其做增删操作,所以字符串没有这几个方法也算合理。

    列表的 clear() 方法会清空列表,用来节省内存空间,效果等于anylist[:] = [],但是,奇怪的是,Python 并不支持清空/删除操作。

    首先,字符串没有 clear() 方法,其次,它是不可变对象,不支持这种赋值操作anystr[:] = '',也不支持del anystr[:]操作:

    s = 'Hello world'

    s[:] = ''
    >>> 报错:TypeError: 'str' object does not support item assignment

    del s[:]
    >>> 报错:TypeError: 'str' object does not support item deletion

    当然,你也别想通过del s来删除字符串,因为变量名 s 只是字符串对象的引用(挖坑,以后写写这个话题),只是一个标签,删除标签并不会直接导致对象实体的消亡。

    如此看来,想要手动清空/删除 Python 字符串,似乎是无解。

    最后还有一个 copy() 方法,这就是拷贝嘛,可是字符串也没有这个方法。为什么呢?难道拷贝字符串的场景不多么?在这点上,我也没想出个所以然来,搁置疑问。

    通过以上几个常用列表操作的比较,我们可以看出字符串这种序列是挺受限的。列表可以看成多节车厢链接成的火车,而字符串感觉就只像多个座椅联排成的长车厢,真是同源不同相啊。

    (2)比就比,谁怕谁

    接下来,又到了 Python 字符串与 Java 字符串 PK 的时刻。在对象定义的角度上,Python 的确更胜一筹,这次看看会比出个啥结果吧。

    Java 中有比较字符串的方法,即 compareTo() 方法与 equals() 方法,前一个方法逐一比较两个字符串的字符编码,返回一个整型的差值,后一个方法在整体上比较两个字符串的内容是否相等。

    Python 字符串没有这两个单独的方法,但要实现类似的功能却很简便。先看例子:

    myName = "Python猫"
    cmpName = "world"
    newName = myName

    # 直接用比较符号进行compare
    myName > cmpName  
    >>> False
    myName == newName
    >>> True
    cmpName != newName
    >>> True

    # 比较是否同一对象
    myName is cmpName
    >>> False
    myName is newName
    >>> True

    上例中,如果把赋值的字符串换成列表或者其它对象,这些比较操作也是可以进行的。也就是说,作比较的能力是 Python 公民们的一项基本能力,并不会因为你是字符串就给你设限,或者给你开特权。

    与此类似,Python 公民们自带求自身长度的能力,len() 方法是内置方法,可以直接传入任意序列参数,求解长度。Java 中则要求不同的序列对象,只能调用各自的 length() 方法。说个形象的比喻,Python 中共用一把秤,三教九流之辈都能拿它称重,而Java 中有多把秤,你称你的,我称我的,大家“井水不犯河水”。

    Python 中曾经有 cmp() 方法和__cmp__()魔术方法,但官方嫌弃它们鸡肋,所以在Python 3 中移除掉了。虽然在 operator 模块中还为它留下了一脉香火,但保不定哪天就会彻底废弃。

    import operator
    operator.eq('hello''name')
    >>> False
    operator.eq('hello''hello')
    >>> True
    operator.gt('hello''name')
    >>> False
    operator.lt('hello''name')
    >>> True

    (3)墙上的门

    在 Java 中,字符串还有一个强大的 valueOf() 方法,它可以接收多种类型的参数,如boolean、char、char数组、double、float、int等等,然后返回这些参数的字符串类型。 例如,要把 int 转为字符串,可以用 String.valueOf(anynum) 。

    Python 字符串依然没有这个单独的方法,但要实现相同的功能却很简便。对Python来说,不同的数据类型转换成字符串,那是小菜一碟,例如:

    str(123) >>> '123'
    str(True) >>> 'True'
    str(1.22) >>> '1.22'
    str([1,2]) >>> '[1, 2]'
    str({'name':'python''sex':'male'})
    >>> "{'name': 'python', 'sex': 'male'}"


    而从字符串转换为其它类型也不难,例如,int('123') 即可由字符串'123'得到数字 123。对比 Java,这个操作要写成 Integer.parseInt('123')。

    在Java 的不同数据类型之间,那道分隔之墙矗立得很高,仿佛需要借助一座更高的吊桥才能沟通两边,而在灵活的 Python 里,你可以很方便地打开墙上的那扇门,来往穿越。

    小结一下,跟 Java 相比,Python 字符串确实没有几项方法,但是事出有因,它们的天赋能力可不弱,所有这些操作都能简明地实现。一方面,Python 字符串做不到某些事,但是另一方面,Python 可以出色地做成这些事,孰优孰劣,高下立判。


    640?wx_fmt=png

    总结


    写文章贵在善始善终,现在给大家总结一下:

    本文主要介绍 Python 字符串特有的操作方法,比如它的拼接、拆分、替换、查找及字符判断等使用方法,从正向回答,Python 字符串能做什么?最后,我们还从反向来回答了 Python 字符串不能做什么?有些不能做,实际上是 不为,是为了在其它地方更好地作为,归根到底,应该有的功能,Python 字符串全都有了。

    本文中还将 Python 与 Java 做了比较,有几项小小的差异,背后反映的其实是,两套语言系统在世界观上的差异。古人云,以铜为镜,可以正衣冠。那么,在编程语言的世界里,以另一种语言为镜,也更能看清这种语言的面貌。希望这种跨语言的思维碰撞,能为你擦出智慧的火花。

    作者:豌豆花下猫,某985高校毕业生, 兼具极客思维与人文情怀。公众号Python猫,专注Python技术、数据科学和深度学习,力图创造一个有趣又有用的学习分享平台。

    声明:本文为作者投稿,版权归作者个人所有。


     热 文 推 荐 

    ☞ 力压今日头条成 App Store 榜第一,个税 App 惊爆 62 例木马病毒!

    ☞ 雷军:执掌金山纯属意外

    ☞ 程序员如何玩转汇编指令?

    无业务不技术:那些誓用区块链重塑的行业,发展怎么样了?

    ☞ 下一次 IT 变革:边缘计算(Edge computing)

    ☞ 12306 脱库 410 万用户数据究竟从何泄漏?

    年度重磅:《AI聚变:2018年优秀AI应用案例TOP 20》正式发布

    ☞ 老程序员肺腑忠告:千万别一辈子靠技术生存!

    print_r('点个好看吧!');
    var_dump('点个好看吧!');
    NSLog(@"点个好看吧!");
    System.out.println("点个好看吧!");
    console.log("点个好看吧!");
    print("点个好看吧!");
    printf("点个好看吧!\n");
    cout << "点个好看吧!" << endl;
    Console.WriteLine("点个好看吧!");
    fmt.Println("点个好看吧!");
    Response.Write("点个好看吧!");
    alert("点个好看吧!")
    echo "点个好看吧!"

    640?wx_fmt=gif点击“阅读原文”,打开 CSDN App 阅读更贴心!

    640?wx_fmt=png喜欢就点击“好看”吧!
    展开全文
  • 可变类型:数字,字符串,元组 可变类型:列表,字典 不可变类型运算举例 不可变+= 不可变=+ 不可变类型在进行+=和=+之后结果是一样可变类型运算举例 可变+= 可变类型+=情况 可变=+ 可变类型a=a+b情况 ...
  • python中常用序列结构有字符串、列表、元组、字典、集合。 序列按照是否有顺序分为有序序列和无序序列,以及根据元素是否可以增删改操作分为可变序列和不可变序列。 列表 列表(list)是最重要Python内置对象...
  • 首先明确一下复制含义:复制分为两种,一种是值复制,一种是地址复制。二者看起来都一样,但是区别在于值赋值本质上是生成了...不可变变量数值类型int、long、bool、float,字符串str,元组tuple。如果我们要对不可.
  • python学习

    2020-08-04 01:15:24
    python print(id(i))id是地址 直接i=1,i是不可变的数据类型 某个地址值不可变,即不可变数据类型 Linux同步命令 scp 1.解释性语言和编译性语言区别,...6.字符串类型(不可变类型)操作:split(分割)、repl
  • 我在书上看到了这样代码段 然后我想如果不用list可以吗,于是做了以下尝试 这种情况是因为在python中字符串是不可变对象,不能通过下标方式直接赋值修改 ...
  • Python应用程序设计3.6 集合目录12集合概述集合的操作方法 集合概述在计算机中的集合与数学中概念相同是指一个无序的不重复元素序列使用一对大括号{}表示集合不能有重复的元素如果定义的时候包含重复元素在生成后会...
  • 这到题用到了字符串的所有字母大写和所有字母小写和字符串拼接,复制,用到的函数有 json将列表中的内容按照指定字符连接成一个字符串, upper() 所有字母大写 和lower() 所有字母小写 含有内置函数enumerate ...
  • # tuple:不可变,保证数据不丢失 red, green, blue = tuple(map(lambda e: [data[i] for i in range(0, len(data)) if i % 3 == e], [0, 1, 2])) pixels = tuple(zip(red, green, blue)) return pixels #...
  • Python 中都是引用

    2011-05-25 12:48:00
    大二寒假,在家没事看python,当看到python中数字是不可变的时候,我就看不下去了。如果i = i + 1这样简单运算都要产生一个新变量,这是多么低效啊,明明直接往那块内存写入一个新值不就行了吗。  现在,...
  • Python基础教程 第二版

    2018-04-04 12:35:58
    2.4 元组:不可变序列 2.4.1 tuple函数 2.4.2 基本元组操作 2.4.3 那么,意义何在 2.5 小结 2.5.1 本章新函数 2.5.2 接下来学什么 第3章 使用字符串 3.1 基本字符串操作 3.2 字符串格式化:精简版 3.3 字符串格式...
  • 序列 序列(sequence) 1.1 基本概念 序列是Python中最基本的一种数据结构。序列用于保存一组有序的数据,所有的数据在序列当中都有一个唯一的位置...不可变序列(序列中的元素不能改变):例如 字符串(str)...
  • Python中,数值类型(int和float)、字符串str、元组tuple都是不可变类型。而列表list、字典dict、集合set是可变类型 可变对象中都保存了三个数据 • id(标识) • type(类型) • value(值) 3. 字典简介 3.1 字典...
  • 纯新手自学记录

    2018-10-08 15:55:06
    纯新手的自学记录 时间:2018年10月7日 自身情况:大四三本学历,非科班生 学习天数:2 学习时长:5小时 学习语言:Python 学习内容:进一步接触字符...函数中的可变参数变成列表后不能应用,无法熟练地将input的数...
  • 1.5 基础

    2019-04-11 19:58:39
    1.5 基础基础注释字面常量数字字符串单引号双引号三引号字符串是不可变的转义序列原始字符串变量标识符命名数据类型对象逻辑行与物理行缩进总结 基础 只是打印出 hello world 肯定是不够,是吗?你会希望做得比这...
  • 2. 函数参数:默认参数、可变参数、关键字参数 3. 变量作用域:局部变量和全局变量 4. 匿名函数定义及使用 5. 高级函数(map、reduce、filter)使用 (五)面向对象程序设计 【考试要求...
  • 1. if-elif-else 语句可以设置多个判断条件? A正确 B错误 2. if-else 语句无论条件是否...5. Python 中的数值、字符串类型数据是不可变类型? A正确 B不正确 6. 变量名 7month 这种写法正确吗? A正确 B不...
  • golang面试题:翻转含有中文、数字、英文字母的字符串 golang面试题:拷贝大切片一定比小切片代价大吗? map不初始化使用会怎么样 map不初始化长度和初始化长度的区别 map承载多大,大了怎么办 map的iterator是否...
  • Python字符串相似性算法库、PyLaia:面向手写文档分析深度学习工具包、TextFooler:针对文本分类/推理对抗文本生成模块、Haystack:灵活、强大的可扩展问答(QA)框架、中文关键短语抽取工具。 1. textfilter: ...
  • 2.2.6 实现一个函数,把一个字符串中的字符从小写转为大写 2.2.7 随机输入一个数,判断它是不是对称数(回文数)(如3,121,12321,45254)。不能用字符串库函数 2.2.8 求2~2000的所有素数.有足够的内存,要求尽量...

空空如也

空空如也

1 2
收藏数 37
精华内容 14
关键字:

python中的字符串可变吗

python 订阅