2018.04.15 已經(jīng)用python一段時間了,最近遇到幾個與字符串相關(guān)的問題,雖然最后都解決了,但很不pythonic,所以決定回補字符串相關(guān)基礎(chǔ)知識。
參考資料:
python3中文版參考-第二章:字符串和文本
小甲魚 字符串:格式化 – 零基礎(chǔ)入門學(xué)習Python015
先看基礎(chǔ)——正則表達
參考:python正則表達式系列(1)——正則元字符
why?因為字符串的處理除了用到python的str方法之外,很多時候還需要用到re正則模塊中更加強大、靈活的方法進行處理,而后者的重要基礎(chǔ)就是正則。因此,想要靈活處理字符串問題,就必須先掌握正則基礎(chǔ)。
正則元字符:. ^ $ * + ? { } [ ] \ | ( )
A 元字符之[ ]——指定字符集
正則表達式[]里的五個特殊字符
通常的字符集匹配:
- [abc]匹配:a或b或c
- [^a]匹配:匹配非a的一個字符;
- [a-zA-Z0-9]匹配:大小寫英文字母和數(shù)字
- [^0-9]匹配:不包含0123456789的其他任意字符
然而,
① [ ] - \ ^五個字符在[ ]中都有著特殊意義,而其余的元字符.、*、+、|在[ ]中均不再保留任何特殊意義;
②因此,若要在[]中匹配[ ]-\^五個元字符一定要添加反義字符 \
- [\^a\-bc]匹配:^和a和-和b和c共五個字符組成的字符集
- [a+]匹配:a或+
- [*\-+]匹配:* - + 推薦!
- [*-+]這個表達式其實表示的是*的ASCII值到+的ASCII值的范圍。不推薦!
- [+-*]將會報錯,就像你不能寫成[9-0]一樣,因為+、*的ASCII值大小順序反了。錯誤!
B 元字符之()——匹配 pattern 并保留匹配符號
正則表達式 - 元字符
(pattern): 匹配 pattern 并獲取這一匹配;
(?:pattern): 匹配 pattern 但不獲取匹配結(jié)果;
(?=pattern):正向肯定預(yù)查(look ahead positive assert),在任何匹配pattern的字符串開始處匹配查找字符串。這是一個非獲取匹配,也就是說,該匹配不需要獲取供以后使用。
(?!pattern):正向否定預(yù)查(negative assert),在任何不匹配pattern的字符串開始處匹配查找字符串。這是一個非獲取匹配,也就是說,該匹配不需要獲取供以后使用。
(?<=pattern):反向(look behind)肯定預(yù)查,與正向肯定預(yù)查類似,只是方向相反。
(?<!pattern):反向否定預(yù)查,與正向否定預(yù)查類似,只是方向相反。
C 元字符之{ }——匹配前一個字符或子表達式出現(xiàn)指定次數(shù)
例如:
- {0,}:0次或多次,相當于*
- {1,}:1次或多次,相當于+
- {0,1}:0次或1次,相當于?
- {m,n}:m次到n次(m <= n)
1 字符串分割:str.split()和re.split()
參考:
Python字符串分割方法總結(jié)
中文說明 2.1 使用多個界定符分割字符串
1.1 str.split()方法
S.split(sep=None, maxsplit=-1)
返回的是一個list
- sep為分隔符,默認以空白字符whitespace (空格,TAB和回車)為分隔符;
- maxsplit為最大分割次數(shù),當指定最大分割次數(shù)maxsplit時,結(jié)果列表長度為maxsplit+1。;
- print(str.split._ doc _)查看相關(guān)說明
- 缺點:sep只能指定一個分隔符??!
1.2 re.split()方法
re.split(pattern, string, maxsplit=0, flags=0)
返回的是一個list
- pattern相當于sep的功能,但它是更加靈活的正則表達式;
- string為目標字符串;
- maxsplit為最大分割次數(shù),當指定最大分割次數(shù)maxsplit時,結(jié)果列表長度為maxsplit+1;
- flags為標志,表示正則表達式用到的標志。
核心:可以用靈活的正則表達式作為分隔符
①用[ ]符號:表示字符集,無需再用或,也不加逗號。
import re
line = 'asdf fjdk; afed, fjek,asdf, foo'
re.split(r'[,;\s]\s*', line)
Out[5]: ['asdf', 'fjdk', 'afed', 'fjek', 'asdf', 'foo']
②用()符號:保留分割符號
line = 'asdf fjdk; afed, fjek,asdf, foo'
fields = re.split(r'(;|,|\s)\s*', line)
Out[6]: ['asdf', ' ', 'fjdk', ';', 'afed', ',', 'fjek', ',', 'asdf', ',', 'foo']
2. 字符串開頭、結(jié)尾匹配:str.startwith()、str.endwith()
經(jīng)常用于文件名、擴展名的快速優(yōu)雅匹配
>>> filename = 'spam.txt'
>>> filename.endswith('.txt')
True
>>> filename.startswith('file:')
False
返回的是True、False,經(jīng)常用作if 的判斷參數(shù),將if嵌入for循環(huán)中進行列表快速篩選!
經(jīng)典用法1:快速篩選有效數(shù)據(jù)生成list
>>> filenames
[ 'Makefile', 'foo.c', 'bar.py', 'spam.c', 'spam.h' ]
>>> [name for name in filenames if name.endswith(('.c', '.h')) ]
['foo.c', 'spam.c', 'spam.h'
經(jīng)典用法2:檢查某個文件夾中是否存在指定的文件類型
if any(name.endswith(('.c', '.h')) for name in listdir(dirname)):
str.startwith()、str.endwith()的功能用切片比對的方法也能實現(xiàn),但那樣很不優(yōu)雅!
3.用通配符匹配字符串:fnmatch() 和 fnmatchcase()
與前述的str.startwith()、str.endwith()是字符串精準匹配,而fnmatch() 和 fnmatchcase()可以用通配符進行更加靈活的匹配
from fnmatch import fnmatch, fnmatchcase
#導(dǎo)入fnmatch模塊的相關(guān)方法
fnmatch('foo.txt', '*.txt')
經(jīng)典用法:
import fnmatch
import os
for file in os.listdir('.'):
if fnmatch.fnmatch(file, '505996-*-2017.txt'):
print(file)
4.字符串匹配和搜索:str.find() , str.endswith() , str.startswith()和re.match()
str.find():返回的是字符串在str中第一次出現(xiàn)的位置(int)
text = 'yeah, but no, but yeah, but no, but yeah'
text.find('no') #返回的是字符串在str中第一次出現(xiàn)的位置(int)
10
re.match():
text1 = '11/27/2012'
if re.match(r'\d+/\d+/\d+', text1):
print('yes')
5.字符串中插入變量:{}和format()方法
>>> s = '{name} has {n} messages.'
#用{ }來定義變量
>>> s.format(name='Guido', n=37)
#用str.format(變量=vlaue)來給字符串中的變量賦值
out: 'Guido has 37 messages.'
應(yīng)用場景:爬蟲中多頁的url地址,切換{num}url中的頁碼變量