字元串的一些對齊, Join, strip, 和拼接性能上用 生成器等小 tips
我始終是覺得, 在處理字元串這塊, 兩個重要點是, split 分割, 和 正規表達式這兩個大頭, 其餘的還好吧. split 是為了處理結構化, 規則明确的 "分割", 正則則是萬能的, 尤其是 re.match, re.findall, re.sub ... 是經常會用到的. 然後呢, 這裡繼續來一些修修補補的内容哇, 主要也是再留個印象, 和為自己以後用到時會首先搜尋一波自己的筆記.
果然, 搞來搞去, 還是最基本概念, 基本功最為重要的. 而并非什麼新算法, 架構, 項目啥的, 都搞膩了...
删除不需要的字元
需求
需删除字元串的開頭, 結尾或中間不想要的字元, 比如空白.
方案
用 字元串的 strip() 實作, 衍生的 lstrip() 和 rstrip() 分别從左, 右, 執行删除特定字元 (預設删除 "空格")
s = ' hello world \n'
# strip 預設删除空白, 并傳回新對象哦
print('raw:', s)
print('both:', s.strip())
print('left:', s.lstrip())
print('right:', s.rstrip())
# 删除特殊字元
t = '------youge========'
print('raw:', t)
print('left:', t.lstrip('-'))
print('right', t.rstrip('='))
print('both', t.strip('-='))
raw: hello world
both: hello world
left: hello world
right: hello world
raw: ------youge========
left: youge========
right ------youge
both youge
大多數情況下, 直接用 strip() 就基本能搞定了. 但有個 bug 是, 對于字元串中中間的文本空格, 并不産生影響.
s = 'hello world youge !\n'
print(s.strip())
hello world youge !
這就非常的雞肋了. 中間的 空格, 我自己還得用 replace () 來處理, 要這 strip() 有何用 ...
'# 來一波, 鍊式調用...
s.strip().replace(' ', '')
'helloworldyouge!'
我最近的一個場景是, 用正則比對特殊字元, 并進行替換.
re.complie(u"[\U00010000-\U0010ffff]")
用的比較多就是檔案處理, 像資料類的如 Excel, csv 這些,我會用到 DataFrame 來處理, 其實很笨, 周遊每個單元格來查找特殊字元并替換. 其次是一般的檔案處理, 結合生成器來弄.
# 結合生成器
with open(file_name) as f:
lines = (line.strip() for line in f)
# 生成器兩種方式: 元組推導時 或者 函數中使用 yield 代替 return
# 生成器,運作時不占記憶體, 真正用時才會 "懶加載"
for line in lines:
print(line)
字元串對齊
需求
對字元串進行 左對齊, 右對齊, 居中對齊等...
方案
用 ljust(), rjust(), center() 來實作即可. 當然, 我感覺真實中的用處并不大, 我是基本沒有用到過.
text = "hello, world!"
print("左對齊:", text.ljust(20))
print("右對齊:", text.rjust(20))
print("居中對齊:", text.center(len(text)))
print("補全:", text.ljust(50, "*"))
左對齊: hello, world!
右對齊: hello, world!
居中對齊: hello, world!
補全: hello, world!*************************************
然後還有格式化的常用 3個方法: %s, format(), f"({variable})". 就不展開了. %s 這種占位符方式, 我在拼接 sql 的時候, 就執拼接 executemany( 'insert into tb_name ..', args=xxx) 會用到. 自用我用了 f"{變量}" 的寫法後, 就再也沒有用過 format() 方法了, 覺得不夠簡潔和優雅呢.
字元串拼接
需求
跟 split() 逆向操作, 即要把幾個小的字元串合并為一個大的字元串
方案
用 join( ) 函數可實作 一些 序列或者 iterable 中, 更加簡單的用 "+" 即可.
words = ['nice', 'to', 'see', 'you']
# 用空格來拼接為一個字元串
print(' '.join(words))
# 用自定義符号來拼接
print("* ".join(words))
nice to see you
nice* to* see* you
更加簡單的字元串拼接, 用 "+", 注意, 正好最近在看 js 代碼嘛, 需要說明一下, 正好做一個對比學習.
- Pyhton 是一門 動态(無需聲明變量類型), 強類型 語言 (比如 字元串 是不能 和 數字 "拼接" 運算的)
- JavaScript 是一門, 動态, 弱類型 語言 (在 js 中, 數字和字元串是可以運算的, 就很不嚴謹, 我感覺
a = 'how'
b = 'are'
c = 'you'
print(a + ' ' + b + ' ' + c)
how are you
我怎麼, 感覺現在我經常來看這些基礎的問候語句的時候, 覺得境界不一樣了, 像, "hello, world", 人生若隻如初見, "how are you ", 你還好嗎 ... 這類的話語格外溫暖和親切.
字元串拼接,這樣一個看似極為基礎的事情, 讨論的意義, 更多是有性能方面考量的. 需注意的是, 當我們使用 "+" 操作符去大量連接配接字元串的時候, 效率是非常低的. 因為 "+" 會引起記憶體複制和垃圾回收.
# 反例: 希望我以後再也不要這樣寫
s = ''
for i in words:
s += i
不推薦用 "+" : 每次執行 "+= " 的時候, 都會建立一個新的字元串對象
那推薦的, 自然是使用生成器表達式來進行合并了呀, 結合 join 來處理, 這才簡潔優雅哦, 簡潔不是簡單呢.
lst = ['My', 'score', 'is', 99.66]
print(
','.join(str(i) for i in lst)
)
My,score,is,99.66
查了下, 也不是絕對哈. 當混合使用 I/O 操作的時候, 需要具體來研究一下程式.
# v1:
f.write(s1 + s2)
# v2:
f.write(s1)
f.write(s2)
如果兩個字元串非常小, v1 版本反而會更好些, 因為 I/O 操作本就是一個耗時操作哦; 但當非常大的時候, v2 的優勢就展現出來了, 因為它避免了, "+" 會不斷建立臨時結果且需要複制大量的記憶體資料塊.
如果是要寫一個大量小字元串的輸出代碼, 可以考慮使用生成器, 用 yield 來輸出片段.
def sample():
yield 'how'
yield 'are'
yield 'you'
yield 'youge'
# list(sample())
# 可以用 join() 将這些片段合并起來
' '.join(sample())
# 或者重定向到檔案
for i in sample:
f.write(i, '\n')
# 來一個混合方案, 結合 I/O 操作
def combine(source, maxsize):
lst = []
size = 0
for part in source:
lst.append(part)
size += len(part)
# maxsize 作為一個門檻值
if size > maxsize:
yield ' '.join(lst)
# 然後再重新計數, 進入下一輪
lst = []
size = 0
yield ' '.join(lst)
# 結合檔案操作
with open('youge.txt', 'w') as f:
for part in combine(sample(), 12345):
f.write(part)
這樣一來, 用上生成器後, 整個代碼的美感就上來的, 簡潔, 優雅, 高性能, 是我喜歡的.
耐心和恒心, 總會獲得回報的.