Pandas 清除 Excel 特殊字符


清除 Excel 特殊字符

主要是為了做一個筆記, 用 遍歷 DataFrame 用正則匹配特殊字符並替換.

是上個月初的項目了, 其中有個將 Excel 傳入數據庫的時候, 發現有特殊字符, 很奇怪的那種特殊字符, 什么小五角星, 小書書, 小太陽, 耳機 等這種字符, 真的好奇怪. 后來發現, 這種問題竟然是經常出現, 於是來做個筆記, 方便自己以后再遇到的時候, 能輕松復制粘貼.

需求

清除 Excel 的特殊字符, 諸如 小星星, 小花花, 小太陽, 小提琴, 小耳機 ... 等這些小可愛.

輸入是一個 Excel 表格, 輸出去 清除 (替換) 掉特殊字符的 Excel 表格 ( 跟輸入一樣) .

方案

  • 特殊字符匹配用 正則表達式在查詢並替換 re.compile(); re.sub();

  • 用 Pandas 讀取 Excel 數據為 DataFrame

  • 遍歷 DataFrame 的每個格子, 進行正則匹配 並替換 df.loc 和 iloc

查找特殊字符並替換

找了好久的規律, 仔細琢磨發現的, 那些特殊字符是可用 unicode 進行匹配出來.

[\U0001000 - \U001ffff]

然后呢, 我們的操作就是, 查找, 並並進行替換, 封裝為一個函數哦.

def replace_spec_char(char, replace_char):
    """替換掉特殊字符, 用某種自定義標記"""
    
    if not isinstance(char, str):
        return "輸入的是非字符串哦"
    
    pattern = re.compile(u'[\U0001000 - \U001ffff]')
    # 替換
    return pattern.sub( replace_char, char)
    

遍歷 DataFrame 並清理

用下標索引 iloc 的方式來弄即可. 其實關於 df.loc 和 df.iloc 我從來就沒有真正記住和區分過, 大約只是記得 loc 用於有名字的 所有, 如字段啥的. iloc 是按照下標索引.

而我想表達的學習方法是, 根本不用去刻意記, 有印象和臨時百度就好啦. 就好比, 我始終不能區分 json.loads() 和 json.dumps() ; 或者 eval() 和 __ repr __ () ; 或者 pandas / numpy 中 的 軸 axis = 1 或 0 ... 這類到底是啥的問題,

解決之道 是 留大概印象, 即用即查.

def parse_data(file_path, replace_char):
    """替換 Excel 特殊字符"""
    try:
        df = pd.read_excel(file_path):
    except:
        raise "數據讀取異常"
    # 遍歷每個單元格, 先行后列我比較習慣而已
    row, col = df.shape
    for i in range(row):
        for j in range(col):
            # 當前格元素, 發現上面寫不對, 字符校驗應該在這里
            cur_value = df.iloc[i, j]
            pure_char = replace_char(cur_value, replace_char)
            # 把特殊字符, 及其所在的行列坐標給打印出來
            if cur_value != pure_chare:
                print(f"特殊字符: {cur_value} 位於 {i+1}行, {j+1}列.")
                # 並同時將當前值用 清理好的字符替換
                df.iloc[i, j] = pure_char
                
    print("清理完畢!")
    

遍歷DF 的 cell

還是稍微演示一把好一點.

df = pd.DataFrame({
    'name':['youyou', 'youge', 'jieer'],
    'age': [18, 22, nan],
    'gender': ['F', nan, 'M']
})

df
	name	age	  gender
0	youyou	18.0	F
1	youge	22.0	NaN
2	jieer	NaN	     M
# 我個人喜歡按 row 來進行遍歷哦
row, col = shape
for i in range(row):
    for j in range(col):
        print(df.iloc[i, j]ue,'\t\t', type(df.iloc[i, j]))
youyou 		 <class 'str'>
18.0 		 <class 'numpy.float64'>
F 		     <class 'str'>
youge 		 <class 'str'>
22.0 		 <class 'numpy.float64'>
nan 		 <class 'float'>
jieer 		 <class 'str'>
nan 		 <class 'numpy.float64'>
M 		     <class 'str'>
for i in range(df.shape[0]):
    for j in range(df.shape[1]):
        cur_value = df.iloc[i, j]
        if isinstance(cur_value, str):
            df.iloc[i, j] = "是字符"

# df.iloc[i, j] = 'xxx' 是原地的哦            
print(df)
    name   age	  gender
0	是字符  18.0   是字符
1	是字符	 22.0	NaN
2	是字符	 NaN	是字符

完整實現

上面的代碼呢, 后面的函數, 嵌套了前面的函數. 我之前覺得沒啥, 后來跟小伙伴, 他做 Java 的, 然后聊了一波 面向對象, 同時也是, 之前接了一波同事的 數據處理代碼, Python 的面向對象寫法. 我發現, Python 的面向對象寫法, 其實不太好. 一不小心就, 容易, 代碼給 混在一起, 互相調用, 容易搞成 高耦合., 別人很難去維護.

至少是腳本這塊哈, 我希望自己是:

可能更傾向於, 函數式編程的模式;
或者說, 一個函數一個功能, 盡可能解耦, 最后用 main 來調用.

從本例, 就盡量,不要出現, 第二個 一個函數中, 調用 另一個函數 的風格. 這種可以寫在 main 中, 就這樣吧. 重在理解過程和讓代碼可讀性更強一些.

def replace_spec_char(char, replace_char):
    """替換掉特殊字符, 用某種自定義標記"""
      # 匹配並進行替換
    pattern = re.compile(u'[\U0001000 - \U001ffff]')
    return pattern.sub( replace_char, char)
    
def get_data(file_path):
    """將 Excel 數據讀入為 DataFrame"""
    try:
        df = pd.read_excel(file_path)
    except:
        raise "數據讀取異常!"
    return df


def main():
    data = get_data(file_path)
    # 獲取data 的行, 列數, 並進行遍歷
    row, col = data.shape
    # 遍歷每個 cell, 並對字符串的 cell 進行清洗
    for i in range(row):
        for j in range(col):
            # cell 值
            cur_value = data.iloc[i, j]  
            # 只對字符如進行清洗
            
            if isinstance(cur_value, str):
                pure_char = replace_spec_char(char, replace_char)
                
                # 跟清洗前做比對, 打印出特殊符行列號
                if cur_value != pure_char:
                    print(f"特殊字符: {cur_value} 位於 {i+1}行, {j+1}列.")
                    
                    # 同時將當前個用清理好的進行原地替換
                    data.iloc[i, j] = pure_char
                    
    print("清理完畢")

因為我經常會用到, 因此還打了個包, exe 的, 哎呀不寫了, 打包用 pyinstaller 又不難的, 不展開了.

小結

  • 匹配特殊字符, 結合強大的正則表達式, 如 re.compile(), re.sub(), re.match(), re.findall ( ) 都很常用
  • 遍歷 DataFrame 用索引方式 df.iloc 速度還行. 遍歷這塊, 同樣 df.iterrows() 也是我常用的呢
  • 原地替換 data.iloc[i, j] = 666 簡單又暴力, 現腳本這塊更傾向函數式編程, 尤其是解耦和可讀性, 我覺得更重要


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM