一個用來從字串中移除標點符號的 Python 正則表達式是 re.sub(r'[^\w\s]', '', text) — 一行程式,十一個字元的樣式,所有逗號、句號和引號都在一次處理中消失。問題在於,這個同樣的樣式也會吞掉像 $、+ 和 = 這類符號,並吃掉表情符號,因為被反轉的字元類會把任何不是文字字元或空白的東西都當成可棄置的。對於真實的文字 — 產品價格、社群文案、多語言段落 — 這種過度清除是一個錯誤,而不是功能。Unicode 解決了這個問題:標點符號是獨立的類別,與符號分開,而支援 Unicode 的正則表達式 \p{P} 只會對準七個標點符號子類別,同時保留貨幣符號、數學運算子和表情符號在原位。如果你想要這種精確度,卻又不想寫任何一行 Python,移除標點符號 工具會在瀏覽器中套用同樣經 Unicode 驗證的規則,並提供切換選項來保護單字內部的撇號和連字號,這些在一個嚴格的正則表達式中會被破壞。

快速解答:一個可運作的 Python 標點符號正則表達式
Python 中最快的一行解法是 re.sub(r'[^\w\s]', '', text),它會刪除所有不是文字字元或空白的字元。在 Python 3 下,\w 預設就支援 Unicode,所以這個樣式已經涵蓋任何文字系統的字母,但它仍然會把符號和表情符號視為可移除的。經典的初學者範例看起來像這樣:import re; text = "Hello, world! It's $19.99 + tax."; clean = re.sub(r'[^\w\s]', '', text),其結果為 "Hello world Its 1999 tax"。注意有兩個問題:撇號從 It's 中消失了,讓這個縮寫看起來像拼錯字,而 $ 和 + 與句號一起被吃掉,產生了毫無意義的 1999 而非 19.99。一旦你知道這個正則表達式實際上在做什麼,這兩個結果都是可預期的 — 它不是在「移除標點符號」;它是在「移除所有不是字母或空格的東西」。如果你想保留 $ 符號,那麼這個樣式就需要允許符號通過,而這正是大多數教學文章變得不再有用的地方。
許多指南反而推薦 string.punctuation,它是常數 !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~。該樣式會變成 re.sub('[' + re.escape(string.punctuation) + ']', '', text) 或 str.translate(str.maketrans('', '', string.punctuation))。這更乾淨、更快速,但它只涵蓋 ASCII 標點符號 — 每個全形 CJK 符號、每個智慧引號、每個歐式破折號都不在這個常數範圍內。如果你的文字完全是英文,結果是正確的;如果不是,你就帶著一個沉默的錯誤出貨了。
為什麼一般的正則表達式會在符號和表情符號上失效
字串 ".+😀" — 一個句號、一個加號和一個笑臉表情符號 — 在 [^\w\s] 之下都落入同一個分類,因為它們沒有一個是文字字元或空白。從 Python 的角度來看,它們同樣不合格,所以它們被同樣刪除。對於合成的測試來說這沒問題,但對於任何提到價格、數學或社群文案的文字來說卻是災難性的。你可以在 Unicode 字元資料庫 中查到實際的 Unicode 分類,把它清楚切開:標點符號屬於 P 類別(連接號、破折號、開頭、結尾、起始引號、結尾引號、其他),而符號屬於 S 類別(數學、貨幣、修飾、其他),表情符號也住在符號領域。忽略這些區分的正則表達式總是會過度清除。
第二個問題是 [^\w\s] 在混合語言的文字上會悄悄地行為失常。包含全形中文句號 。 — U+3002 IDEOGRAPHIC FULL STOP — 的句子,其行為與 ASCII 句號不同,而位於 U+FF0C 的全形逗號 , 需要被明確處理。初學者教學文章的作者很少在 CJK 文字上測試,所以這些錯誤會一直隱藏,直到使用者貼上一段中文段落,得到的結果與英文教學所承諾的不同。
這也是為什麼一個聲稱可以清除標點符號的工具可能會被包裝成解決兩種不同工作中的一種:把標點符號從文字中清乾淨,或是把所有不是字母或數字的東西從文字中清乾淨。第二種工作本質上就會吃掉符號和表情符號。第一種工作才是你真正想要的,而正則表達式必須寫得更仔細才能做到。
使用 \p{P} 與 Unicode 標準走向 Unicode 感知
Python 內建的 re 模組,雖然支援 Unicode,卻不像 JavaScript 那樣原生接受 \p{P} 作為 Unicode 屬性跳脫。MDN 關於 Unicode 字元類跳脫的參考資料 描述 \p{P} 為比對每一個 Unicode 標點字元,這正是你想要的範圍 — 而且 JavaScript 引擎,加上第三方的 Python regex 模組,兩者都遵守它。要在純 CPython 中獲得等效行為,實際的選項包括:
- 使用 str.translate 和 string.punctuation 建立一個轉換表,這可以乾淨地處理 ASCII,但會漏掉 CJK 標點符號。
- 使用第三方的 regex 模組,它確實支援 \p{P},並提供與帶有 u 旗標的 JavaScript 正則表達式相同的精確度。
- 手動在一個字元類中列舉七個 Unicode 標點子類別 — 一段又長又醜的範圍字串,必須與新的 Unicode 版本保持同步。
對於大多數撰寫臨時清理腳本的人來說,這就是正則表達式不再感覺像快速修補的時刻。這個樣式已經不再是一個句子;它變成了一份維護合約。
如何在不自己寫正則表達式的情況下移除標點符號
如果你寧願跳過 Unicode 文獻,只想清理文字,那麼移除標點符號工具會在瀏覽器中執行同樣的分類工作。沒有腳本要託管,沒有旗標會忘記,沒有字元類要維護。經過驗證的操作步驟如下:
- 把你想移除標點符號的文字貼到輸入框中。
- 決定縮寫中的撇號和複合字中的連字號是否應該保留,以及被移除的記號是否應該變成空格而不是直接消失。
- 點擊移除標點符號,檢查移除數量,然後複製結果。
這個工具精確地只移除七個 Unicode 標點子類別 — 連接號、破折號、開頭、結尾、起始引號、結尾引號和其他 — 並透過保留 $、+、=、^、©、貨幣符號和表情符號不動來證明這個範圍。如果你也想把符號移除,特殊字元移除工具 是執行那項工作的姊妹工具;這個頁面存在是為了那些絕對不能發生的情況。一切都在本機執行;沒有任何東西被上傳、儲存或傳送到帳戶,一百萬個字元的貼上一次線性處理只需數毫秒。
保護縮寫和複合字不被清除
清除標點符號真正棘手的部分不是標點符號本身 — 而是含有標點符號的單字。don't、it's、state-of-the-art 和 well-known 不是「標點符號加單字」;它們是內部標點帶有意義的單字。一個粗暴的正則表達式會移除撇號和連字號,悄悄地把這些變成 dont、its、stateoftheart 和 wellknown,然後看起來像拼字錯誤或與相鄰的單字合併。
移除標點符號工具透過兩個切換選項來處理這個問題。撇號切換會在縮寫和所有格中保留鍵盤上的直式撇號以及捲曲的印刷撇號 — ' 的兩種形狀,包括 U+2019 RIGHT SINGLE QUOTATION MARK — 因此 don't 會保持 don't 而不會被折疊。規則是「兩側都是字母或數字」,這代表包圍著單字的引號仍然會被移除。連字號切換對複合字做同樣的處理。well-known 和 state-of-the-art 會保留連字號,而像 2020-2021 這樣的日期範圍會存活,而漂浮在空格之間的破折號仍然會被移除。兩條規則本質上都只作用於單字內部,這帶來一個文件會誠實指出而非隱藏的後果:像 the dogs' bowls 這種尾隨的所有格會失去它的撇號,因為它後面沒有東西。
What Happens to Numbers, Tabs, and Line Breaks
Stripping punctuation also strips decimal points and thousands separators, because the period in 9.99 and the comma in 1,000 are punctuation by Unicode's reckoning. That is what removing punctuation means: 9.99 becomes 999, 1,000 becomes 1000, and 2020-2021 survives only if the hyphen toggle protects the internal dash. If you need the pieces kept apart — for instance, to feed the result into a tokenizer that expects space-separated tokens — flip on the replace-with-space toggle. one,two,three then becomes one two three instead of onetwothree, and the resulting runs of spaces are tidied to single spaces per line without ever merging lines together.
Tabs and line breaks are never touched in either mode, so the shape of your text survives a clean strip. That matters when you are cleaning multi-paragraph input and do not want a single call to flatten the structure. The removal counter reports exactly how many code points were removed, and the operation is idempotent — running the output through again changes nothing, so it is safe to chain with other cleaners or to apply it twice if a downstream step introduces new punctuation you did not anticipate.
| Character | Unicode category | Stripped by a plain regex | Stripped by Remove Punctuation |
|---|---|---|---|
| Comma , U+002C | Punctuation / Other | Yes | Yes |
| Period . U+002E | Punctuation / Other | Yes | Yes |
| Dollar sign $ U+0024 | Symbol / Currency | Yes | No |
| Plus sign + U+002B | Symbol / Math | Yes | No |
| Emoji 😀 U+1F600 | Symbol / Other | Yes | No |
| Apostrophe in don't U+0027 | Punctuation, internal | Yes | No when toggle on |
| Hyphen in state-of-the-art U+002D | Punctuation, internal | Yes | No when toggle on |
| Full-width period 。 U+3002 | Punctuation / Other | No by default | Yes |
Choosing Between a Python Regex and the Browser Tool
Write the regex when you need the strip embedded in a larger pipeline — a data-preprocessing script, a batch job, a CI check. The one-liner re.sub(r'[^\w\s]', '', text) is fine for ASCII-only English text where symbol-over-stripping is acceptable. For anything multilingual, mixed with currency or emoji, or contractually obligated to leave $19.99 readable, switch to a Unicode property regex through the regex module or hand-curate the seven punctuation subcategories.
Use the Remove Punctuation tool when the cleaning is a one-off or an ad-hoc step before pasting the text somewhere else. It encodes the Unicode classification once, maintains it as the standard evolves, and gives you three toggles that no single regex line covers. Either way, the rule is the same: punctuation goes, symbols stay, contractions and compounds survive on purpose, and you should never ship a cleaner that quietly mangles numbers or emoji without telling you.
If you're weighing options, How to Get a Random Word in Python Without Code covers this in detail.
If you're weighing options, How to Remove Special Characters in Google Sheets Cells covers this in detail.