您現在的位置是:首頁 > 籃球
Python|文字處理:用正則表示式替換掉漢字(非英文)中間的空格
- 由 小智雅匯 發表于 籃球
- 2022-01-23
文件中空格怎麼替換
網路上的一些文字,部分會有一些不必要的空格,如果想把空格全部替換掉,使用字串string類的replace()方法即可,如:
str = str。replace(‘ ’,‘’)
但如果是中英文混排的文字,如果想替換掉漢字中間的空格,而保留英文單詞之間的空格,則問題的解決要複雜一些。需要用到正則表示式。
如有以下文件:
行(或段)的首尾、一些漢字之間有不必要的空格,需要替換掉。
用以下Python程式碼即可:
處理後的文字儲存到了new。txt文件:
當然,一些有規律的亂碼也可以處理。
上面有提到全部是中文的簡單處理方法,也可以用一個簡單的正則表示式判斷文件或字串內容是否包含“英文+空格+英文”的形式,然後用一個條件判斷分別處理:
下面需要重點剖析一下上面關於正則表示式的概念及相關的一些內容:
正則表示式是一種用來匹配字串的強有力的武器。它的設計思想是用一種描述性的語言來給字串定義一個規則,凡是符合規則的字串,我們就認為它“匹配”了,否則,該字串就是不合法的。
1 compile()方法
向re。compile()傳入一個字串值,表示編譯一個正則表示式,它將返回一個Regex 模式物件(或者就簡稱為Regex 物件)。
我們在Python中使用正則表示式時,re模組內部會做兩件事情:
I 編譯正則表示式,如果正則表示式的字串本身不合法,會報錯;
II 用編譯後的正則表示式去匹配字串;
如果一個正則表示式要重複使用多次或一些較複雜的正則表示式,出於效率的考慮,我們可以預編譯該正則表示式,接下來重複使用時就不需要編譯這個步驟了,直接匹配。編譯後生成Regular Expression物件。
可以向re。compile()傳入re。IGNORECASE 或re。I,作為第二個引數,讓正則表示式不區分大小寫:
>>> robocop = re。compile(r‘robocop’, re。I)
>>> robocop。search(‘RoboCop is part man, part machine, all cop。’)。group()
‘RoboCop’
2 r‘……’的寫法
r‘……’表示忽略……可中可能存在的跳脫字元,當做普通字元看待;
3 中括號[]
有時候你想匹配一組字元,但縮寫的字元分類(\d、\w、\s 等)太寬泛。你可以用方括號[]定義自己的字元分類。
\d、\w 和\s 分別匹配數字、字母和空格。
\D、\W 和\S 分別匹配出數字、字母和空格外的所有字元。
例如,字元分類[aeiouAEIOU]將匹配所有母音字元(一個任意的母音字母),不論大小寫。
Regex = re。compile(r‘[aeiouAEIOU]’)
也可以使用短橫表示字母或數字的範圍。例如,字元分類[a-zA-Z0-9]將匹配所有小寫字母、大寫字母和數字。
請注意,在方括號內,普通的正則表示式符號不會被解釋。這意味著,你不需要前面加上倒斜槓轉義。、*、?或()字元。例如,字元分類將匹配數字0 到5 和一個句點。你不需要將它寫成[0-5\。],寫成[0-5。]即可。
透過在字元分類的左方括號後加上一個插入字元(^),就可以得到“非字元類”。非字元類將匹配不在這個字元類中的所有字元。例如:
Regex = re。compile(r‘[^aeiouAEIOU]’)
[abc]匹配方括號內的任意字元(諸如a、b 或c)。
[^abc]匹配不在方括號內的任意字元。
插入字元(^)還有另外一種用法,如果用在正則表示式的
最前面,
表明匹配必須發生在被查詢文字開始處。類似地,可以再正則表示式的末尾加上美元符號($),表示該字串必須以這個正則表示式的模式結束。如正則表示式r‘\d$’匹配以數字0 到9 結束的字串。可以同時使用^和$,表明整個字串必須匹配該模式。
^spam 意味著字串必須以spam 開始。
spam$意味著字串必須以spam 結束。
4 \s 和\S
\s 空格、製表符或換行符(可以認為是匹配“空白”字元);
\S 除空格、製表符和換行符以外的任何字元;
5 問號?、星號*、加號+、半形句號.
? 匹配零次或一次前面的分組。
* 匹配零次或多次前面的分組。
+ 匹配一次或多次前面的分組。
。 匹配所有字元,換行符\n除外。
問號?在正則表示式中可能有兩種含義:宣告非貪心匹配或表示可選的分組。這兩種含義是完全無關的。
在字串‘HaHaHaHaHa’中,因為(Ha){3,5}可以匹配3 個、4 個或5 個例項,你可能會想,為什麼在前面花括號的例子中,Match 物件的group()呼叫會返回‘HaHaHaHaHa’,而不是更短的可能結果。畢竟,‘HaHaHa’和‘HaHaHaHa’也能夠有效地匹配正則表示式(Ha){3,5}。
Python 的正則表示式預設是“貪心”的,這表示在有二義的情況下,它們會盡可能匹配最長的字串。花括號的“非貪心”版本匹配儘可能最短的字串,即在結束的花括號後跟著一個問號。
{n,m}?或*?或+?對前面的分組進行非貪心匹配。
大括號{}
表示匹配{}前面分組的次數。
{n}匹配n 次前面的分組。
{n,}匹配n 次或更多前面的分組。
{,m}匹配零次到m 次前面的分組。
{n,m}匹配至少n 次、至多m 次前面的分組。
{n,m}?或*?或+?對前面的分組進行非貪心匹配。
6 \u4e00-\u9fa5
表示漢字unicode編碼方式下的編碼範圍,多達20892方塊字(5*16*16*16=20480)。
後面部分:
最後一個方塊字是龥,yù,呼也。UniCode CJK編碼:U+9FA5,五筆:WGKM
7 小括號()
有時候,你可能需要使用匹配的文字本身,作為替換的一部分。替換時使用\1、\2、\3……。表示“在替換中輸入分組1、2、3……的文字”。(可以理解為需要保留部分)
除了簡單地判斷是否匹配之外,正則表示式還有提取子串的強大功能。match方法配合用()表示的就是要提取的分組(Group)。
比如 ^(\d{3})-(\d{3,8})$分別定義了兩個組,可以直接從匹配的字串中提取出區號和本地號碼:
>>> m = re。match(r‘^(\d{3})-(\d{3,8})$’, ‘010-12345’)
>>> m。group(0)
‘010-12345’
>>> m。group(1)
‘010’
>>> m。group(2)
‘12345’
如果正則表示式中定義了組,就可以在Match物件上用group()方法提取出子串來。
注意到group(0)永遠是原始字串,group(1)、group(2)……表示第1、2、……個子串。
8 Regex物件的sub()方法
正則表示式不僅能找到文字模式,而且能夠用新的文字替換掉這些模式。Regex物件的sub()方法需要傳入兩個引數。第一個引數是一個字串,用於取代發現的匹配。第二個引數是一個字串,即正則表示式。
sub()方法返回替換完成後的字串。如:
resup =re。compile(r‘(\[\d*\])’) # 上標處理
s = resup。sub(r‘\1’, s)
9 re的findall()方法
findall()方法將返回一組字串,包含被查詢字串中的所有匹配。(search()將返回一個Match物件,包含被查詢字串中的“第一次”匹配的文字。)
利用findall()方法,可以找到“所有”匹配的地方。另一方面,findall()不是返回一個Match 物件,而是返回一個字串列表。以下兩種寫法都可以:
list1 = re。findall(pattern,strs)
list1 = pattern。findall(strs)
10 split()方法
split()方法提供強大了字串切割功能,可以按正則表示式指定的字元進行切割,返回一個列表。
如用空格切割:
>>> ‘a b c’。split(‘ ’)
[‘a’, ‘b’, ‘’, ‘’, ‘c’]
用多個空格切割:
>>> re。split(r‘\s+’, ‘a b c’)
[‘a’, ‘b’, ‘c’]
用多個字元進行切割:
re。split(r‘[\s\,\;]+’, ‘a,b;; c d’)
[‘a’, ‘b’, ‘c’, ‘d’]
關於中文字元匹配,為了加深理解,可以再看一下下面的例子:
常用正則表示式,可以總結一下:
?匹配零次或一次前面的分組。
*匹配零次或多次前面的分組。
+匹配一次或多次前面的分組。
{n}匹配n 次前面的分組。
{n,}匹配n 次或更多前面的分組。
{,m}匹配零次到m 次前面的分組。
{n,m}匹配至少n 次、至多m 次前面的分組。
{n,m}?或*?或+?對前面的分組進行非貪心匹配。
^spam 意味著字串必須以spam 開始。
spam$意味著字串必須以spam 結束。
。匹配所有字元,換行符除外。
\d、\w 和\s 分別匹配數字、單詞和空格。
\D、\W 和\S 分別匹配出數字、單詞和空格外的所有字元。
[abc]匹配方括號內的任意字元(諸如a、b 或c)。
[^abc]匹配不在方括號內的任意字元。
字元|稱為“管道”。希望匹配許多表達式中的一個時,就可以使用它。例如,正則表示式r‘Batman|Tina Fey’將匹配‘Batman’或‘Tina Fey’。
正則表示式以外的其它補充:
字串的strip()方法:可以刪除掉字串首尾兩端的空格,包括\n,還可以刪除掉首尾兩端的指定字元,形式如strip([str])。strip()方面的功能可以分解為lstrip()和rstrip()。
附程式碼:
import re
f0 = open(‘new。txt’,‘w’,encoding=“UTF-8”)
#處理文字中的空格,只要含有“英文+空格+英文”就不處理
pattern =re。compile(u“[a-zA-Z]+\s+[a-zA-Z]+”)
with open(‘text。txt’, ‘rU’) as file:
。。。。strs = file。read()
。。。。entxt = re。findall(pattern,strs)
if (not entxt):
‘’‘
。。。。s = s。replace(’。‘ , ’。‘)
。。。。s = s。replace(’,‘ , ’,‘)
。。。。s = s。replace(’!‘ , ’!‘)
。。。。s = s。replace(’?‘ , ’?‘)
。。。。’‘’
。。。。s = strs。replace(‘’,‘’) # 處理全形空格
。。。。s = s。replace(‘ ’ , ‘’) # 處理半形空格(全中文可以使用)
。。。。f0。write(s)
。。。。f0。close()
else:
。。。。pattern =re。compile(r‘([\u4e00-\u9fa5,]{1})\s+([\u4e00-\u9fa5,]{1})’)
。。。。with open(‘text。txt’, ‘rU’) as f2:
……。。str = f2。readline()
……。。while str: # readline()方法讀到最後會返回一個空字元
…………s = str。replace(‘’,‘’) # 處理全形空格
…………s = pattern。sub(r‘\1\2’, str)
…………s = s。strip() + “\n” # strip()方法會把尾端的\n也去掉
…………f0。write(s)
…………str = f2。readline() # readline()方法每次只讀取一行
。。。。f0。close() # 如果不是使用上面的with方法,需要close()後文檔才會寫入nex。tx
-End-