天天看點

字元串 - 删除和拼接

字元串的一些對齊, 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)      

這樣一來, 用上生成器後, 整個代碼的美感就上來的, 簡潔, 優雅, 高性能, 是我喜歡的.

耐心和恒心, 總會獲得回報的.

繼續閱讀