我有一個坦白,會讓正規表示式純粹主義者畏縮:在我職業生涯的最初幾年,我透過從Stack Overflow 中複製貼上、更改一個字元、運行程式碼、看到它失敗並重複直到它碰巧出現來編寫正規表示式。工作。我沒有'不明白這些模式--我欺負他們屈服。速度很慢,更糟的是,我運送的模式很脆弱,我無法做到'看。
修復的是'閱讀理論(儘管我最終做到了)。這是一個視覺測試儀 - 一個我輸入圖案的盒子,一個我粘貼測試字串的盒子,匹配的匹配項會在我改變某些東西的那一刻點亮。突然我可以了 看 為什麼 \d+ 搶到的東西超出了我的預期,或者為什麼我的電子郵件模式拒絕了完全有效的地址。 Regex 不再是一個猜謎遊戲,而是一個緊密的回饋循環。
那'這正是什麼 正規表示式建構器 在 toolz。dev 上是。您編寫模式、丟棄測試資料、切換標誌並即時觀看比賽和捕獲的群組突出顯示。它完全在您的瀏覽器中運行,因此日誌行或用戶資料 you'重新測試,永遠不會上傳到任何地方。本指南是正規表示式參考,我希望 I'當時有 - 我實際上重複使用的模式、完整的作弊表以及可以關閉生產伺服器的一個錯誤。
TL;DR: 將您的圖案和測試字串貼到其中 正規表示式建構器 並切換
g/i/m查看匹配的標誌反白顯示。開始簡單,添加約束以消除誤報,並測試對抗性輸入以避免災難性的回溯。對於提取的數據,將其與配對 json 格式化程式 和 Base64 轉換器. 所有客戶端,全部免費。
正規表示式到底是什麼?
正規表示式 - regex 或 regexp - 是一個描述搜尋模式的緊湊字串。代替 "找到 cat," 這個字;你可以說 "尋找任何五位數," "尋找任何看起來像電子郵件的東西,"或"找到以 ERROR 開頭的每一行。"幾乎所有語言和編輯器都支援它們,這就是該技能如此便攜的原因:學習一次,然後在 JavaScript、Python、your 中使用它 grep,以及您的 IDE's 尋找並替換。
這個概念源自於 20 世紀 50 年代的形式語言理論,Ken Thompson 將其連接到 20 世紀 60 年代的計算中進行文字編輯。歷史對於一個實際原因很重要 I'將回到:"常規&引用;語言有限制,這就是為什麼正規表示式確實無法解析 HTML 等嵌套結構,無論你有多聰明。
我在正常一周內到達正規表示式的位置:在用戶輸入到達資料庫之前對其進行驗證,從非結構化日誌行中提取字段,在整個程式碼庫中進行查找和替換,普通搜尋可以't 表達,並在遷移。這 正規表示式建構器 這是我在接近真實程式碼之前對每一個進行原型設計的地方。
以下是基本組成部分 - 您從中組裝圖案的字母表:
| 語法 | 意義 | 例子 | 比賽 |
|---|---|---|---|
. |
除換行符之外的任何字元 | h.t |
帽子,熱,打 |
\d |
任何數字 (0-9) | \d{3} |
123、456 |
\w |
詞字元(az、AZ、0-9、_) | \w+ |
你好,測試_123 |
\s |
任何空白 | hello\sworld |
你好世界 |
^ |
字串的開始 | ^Hello |
一開始你好 |
$ |
字串結束 | end$ |
結束於結束 |
* |
零或更多 | ab*c |
ac、abc、abbc |
+ |
一個或多個 | ab+c |
abc,abbc |
? |
零或一 | colou?r |
顏色,顏色 |
{n} |
正好是n次 | \d{4} |
2026年 |
{n,m} |
n 和 m 之間 | \d{2,4} |
12、123、1234 |
[abc] |
人物類別 | [aeiou] |
任何元音 |
[^abc] |
否定類別 | [^0-9] |
任何非數字 |
(...) |
捕獲組 | (hello) |
捕獲並引用;你好並引用; |
a|b |
交替(或) | cat|dog |
貓或狗 |
每個開發人員都應該方便哪些正規表示式模式?
這些是 I'經過測試、損壞、修復,現在保存在個人片段檔案中。將它們直接複製到 正規表示式建構器 並向他們丟掉你自己的邊緣箱子。
電子郵件(實用型)
^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
這匹配 [email protected] 和 [email protected],並拒絕 @example.com 或者 user@com. 這裡'不過,重要的誠實是:完整的電子郵件語法 RFC 5322 非常複雜 - 從技術上講,它允許引用幾乎沒有人使用的字串和評論。 Don't 追逐 100% RFC 遵守正規表示式。將實用的 99% 與上述模式相匹配,然後透過發送驗證電子郵件確認地址是真實的。 That'這是我最看到的錯誤:團隊在 " 上燃燒了幾天;airtight"電子郵件正規表示式仍然可以't 從拼字錯誤中告訴真實的收件匣。
網址
^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&\/=]*)$
比賽 https://toolz.dev 和 http://www.example.com/path?query=value;拒絕 ftp://... 和純文字。
美國電話號碼
^(\+1)?[-.\s]?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$
夠靈活 555-123-4567, (555) 123-4567, +1 555.123.4567, 和 5551234567.
IPv4 位址
^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$
嵌套交替強制每個八位元組保持在 0 isl255,因此它正確地拒絕 999.999.999.999.
強密碼檢查
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$
需要至少 8 個字元(小寫、大寫、數字和符號)。這 (?=...) 每個先導都斷言一個條件而不消耗角色--這是一個值得理解的巧妙技巧。
ISO 日期 (YYYY-MM-DD)
^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$
比賽 2026-07-11, 拒絕 2026-13-01 和 2026-02-32.
六角色
^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$
比賽 #4466EE, #abc, #000000.
正規表示式作弊表
保持固定。 It'是我檢查最多的參考。
錨
| 圖案 | 描述 |
|---|---|
^ |
字串的開始(或多行模式下的行) |
$ |
字串結束(或多行模式下的行) |
\b |
詞邊界 |
\B |
非詞邊界 |
量詞
| 圖案 | 描述 |
|---|---|
* |
0 或更多(貪婪) |
+ |
1 個或更多(貪婪) |
? |
0 或 1(貪婪) |
*? +? ?? |
惰性版本 - 盡可能少匹配 |
{n} {n,} {n,m} |
正好 n /n 或更多/在 n 和 m 之間 |
人物類別
| 圖案 | 描述 |
|---|---|
[abc] |
a、b 或 c |
[^abc] |
不是 a、b 或 c |
[a-z] [A-Z] [0-9] |
範圍 |
\d \D |
數字/非數字 |
\w \W |
單字字元/非單字字元 |
\s \S |
空白/非空白 |
團體和環顧四周
| 圖案 | 描述 |
|---|---|
(abc) |
捕獲組 |
(?:abc) |
非捕獲組 |
(?<name>abc) |
命名為捕獲組 |
(?=abc) / (?!abc) |
正面/負面的展望 |
(?<=abc) / (?<!abc) |
正面/負面的向後看 |
旗幟
| 旗幟 | 描述 |
|---|---|
g |
全域 - 尋找所有匹配項 |
i |
不區分大小寫 |
m |
多行 - ^ 和 $ 匹配線邊界 |
s |
點- . 匹配換行符 |
u |
統一碼支援 |
如何在不浪費一個小時的情況下建立和調試模式?
我的過程是故意無聊的,因為無聊是可重複的:
- 從與一個真實範例相符的最簡單的事情開始。 Don'嘗試一次處理每個案件。
- 貼上陽性和陰性測試字串 進入 正規表示式建構器- 應該匹配的事情和不能匹配的事情。
- 收緊以消除誤報。 新增錨 (
^,$) 所以模式與整個字串匹配,然後交換.對於特定的類別,例如[a-z]或者[^,]. - 向其提供對抗性輸入- 空字串、巨大輸入、Unicode 和文字正規表示式字元作為資料。
- 只有這樣才能優化。
當某件事行為不端時,它'幾乎總是三件事之一。如果是的話 匹配太多(,你的量詞是貪婪的 - 讓它們變得懶惰 (*?) 或您的課程更具體。如果是的話 匹配太少,你可能需要 i 標記或忘記逃避特殊角色。如果是的話 完全不匹配,檢查是否有未逃脫的元字元(., *, +, (, [, {(等等)意味著文字或不可見的字符,例如隱藏在測試字串中的選項卡。
什麼是災難性的回溯?為什麼要害怕它?
這是 I'd 部分。如果可以的話,在新開發人員身上紋身。早些時候,我發布了一個看起來完全無辜的輸入驗證正規表示式,一天下午,一個請求將 CPU 核心與 100% 掛鉤並保留在那裡。模式就是問題所在。
當正規表示式引擎可以'找到匹配項時,它 回溯- 它退縮並嘗試其他方法來滿足模式。某些形狀使路徑數量呈指數級爆炸。教科書範例:
^(a+)+$
饋送輸入之類的 aaaaaaaaaaaaaaaaaaaab (一連串 a 以a結尾 b),嵌套量詞為引擎提供了天文數字的劃分方法 as,在結束之前嘗試所有這些;沒有匹配。&引用;您的應用程式凍結。這是一個真正的拒絕服務類別,稱為 雷多斯 (常規表達式拒絕服務),攻擊者確實會利用它。
如何保持安全:
- 切勿嵌套量詞。
(a+)+,(a*)*, 和(a+)*是危險信號。 - 使用原子基團或所有格量詞 引擎支援它們的地方:
(?>a+)或者a++. - 要具體。
[a-z]+回溯小於.+因為它有更少的探索路徑。 - 錨定你的圖案 因此引擎在輸入不匹配時故障很快。
- 使用幾乎匹配但最終失敗的字串進行測試- 那'是回溯的最壞情況。
如果你'正在出發,這個問題根本不存在'不存在,這讓我進入下一節。
Regex 在語言之間有何不同?
核心語法傳播得很好,但細節很吸引人。這些是差異 I'我實際上被絆倒了。
JavaScript:
const regex = /\d{3}-\d{4}/g;
const pattern = new RegExp('\\d{3}-\\d{4}', 'g'); // note the doubled backslashes
'555-1234'.match(regex); // ["555-1234"]
const m = '2026-07-11'.match(/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/);
m.groups.year; // "2026"
小心:lookbehind 才在 ES2018 上市, \d 僅匹配 ASCII 數字,並且 g 標誌製作 .test() 有狀態通過 lastIndex- 循環中的微妙錯誤來源。
蟒蛇:
import re
pattern = re.compile(r'\d{3}-\d{4}') # raw strings avoid double-escaping
pattern.findall('Call 555-1234 or 555-5678') # ['555-1234', '555-5678']
始終使用原始字串 (r'...').記住 re.match 僅在開始時使用錨 re.search 去任何地方尋找。和 re.VERBOSE 讓您編寫多行註釋模式,這對於複雜的模式來說是救星。
PHP: 模式需要分隔符號 ('/\d{3}-\d{4}/'),它使用強大的PCRE發動機,並且 preg_match 回報 1, 0,或者 false 如果有錯誤 - 所以請檢查 ===.
去: 使用RE2發動機,這是故意的 刪除前瞻、後向和後向引用 作為線性時間匹配保證的交換。這意味著甚至不可能發生災難性的回溯--當你選擇一種語言進行不可信輸入匹配時,真正不同的權衡值得知道。
真實範例:解析 Apache 日誌行
這裡'是正規表示式真正擅長的事情。標準 Apache 存取日誌行如下所示:
192.168.1.1 - frank [11/Jul/2026:10:27:10 -0500] "GET /api/users HTTP/1.1" 200 1234
這種模式將其拉開:
^(\S+) \S+ (\S+) \[([^\]]+)\] "(\S+) (\S+) (\S+)" (\d{3}) (\d+)$
將兩者都貼到 正規表示式建構器 每個捕獲的組分別亮起:
| 集團 | 內容 | 例子 |
|---|---|---|
| 1 | IP位址 | 192.168.1.1 |
| 2 | 用戶名 | 弗蘭克 |
| 3 | 時間戳 | 2026 年 7 月 11 日:10:27:10 -0500 |
| 4 | HTTP 方法 | 得到 |
| 5 | 請求路徑 | /api/用戶 |
| 6 | HTTP 版本 | HTTP/1.1 |
| 7 | 狀態代碼 | 200 |
| 8 | 響應大小 | 第1234章 |
一旦各組在測試儀中排列,將其轉換為 a re.findall 在python或a中 match() 在 JavaScript 中是微不足道的 - 您已經知道它有效。
常見問題
什麼是正規表示式建構器?
正規表示式建構器是一種互動式工具,您可以在其中鍵入正規表示式並立即看到它與測試字串匹配,並突出顯示匹配和捕獲的群組。它用即時循環取代了程式碼中緩慢的寫入-運行-失敗-重寫循環。這 正規表示式建構器 在 toolz。dev 上,這完全在您的瀏覽器中完成,因此測試資料保留在您的電腦上。
每種程式語言中的正規表示式模式是否相同?
核心語法幾乎相同,但細節差異足以導致錯誤。較舊的 JavaScript 缺乏後視,Go' RE2 引擎根本沒有前瞻或反向引用,Python 命名群組 (?P<name>...) 在某些情況下。始終確認 you' 語言中的模式實際上是針對性的,而不是假設可移植性。
如何使用正規表示式驗證電子郵件地址?
使用實用的模式,例如 ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$,它處理絕大多數真實地址。不要在正規表示式中嘗試完全符合 RFC 5322 - 語法太複雜,您'仍然會拒絕有效地址或接受拼字錯誤。將正規表示式與驗證電子郵件配對以確認收件匣實際存在。
為什麼我的正規表示式會凍結應用程式?
幾乎總是災難性的回溯。具有嵌套量詞的模式,例如 (a+)+ 當它們遇到幾乎匹配但最終失敗的輸入時,創建指數數量的匹配路徑,並且引擎會嘗試所有這些路徑。刪除嵌套量詞,更喜歡特定的字元類別 .+,並添加錨,以便引擎很快就會失效。
我可以使用正規表示式來解析 HTML 或 JSON 嗎?
不,除了簡單的提取之外,沒有任何其他內容。 HTML 和 JSON 不是常規語言 - 它們允許正規表示式根本無法追蹤的任意嵌套。使用真正的解析器:DOMParser 或 Cheerio for HTML,以及 JSON.parse 或 JSON 的 JSON 工具。當結構嵌套時,正規表示式是錯誤的工具。
什麼'貪婪匹配和懶惰匹配之間的區別?
貪婪量詞 (*, +, ?) 盡可能多地抓取,並在需要時回溯;懶惰的人()*?, +?, ??)盡可能少地抓取,只有在被迫的情況下才會展開。反對 <b>bold</b>,貪婪 <.*> 懶惰時吞下整根繩子 <.*?> 首先停止 <b>. 當模式太匹配時,選擇正確的通常是解決方案。
如何逃脫正規表示式中的特殊角色?
在任何元字元前面放一個反斜線,您的字面意思是: \., \*, \+, \?, \(, \), \[, \], \{, \}, \^, \$, \|, 和 \\。 大多數語言也為您提供了一個逃避整個字串的幫助者 - re.escape() 例如,在 Python 中 - 當字串來自使用者輸入時,這比手動轉義更安全。
正規表示式標誌 g、i 和 m 的意思是什麼?
g (全域)找到每個匹配項而不是停在第一個匹配項上 i (忽略大小寫)使模式對大小寫不敏感,且 m (多行)製作 ^ 和 $ 每條線都匹配,而不僅僅是字串's 開始和結束。他們自由結合,所以 gim 這三個都做嗎? JavaScript 中常見的陷阱:重複使用 a g regex 跨呼叫攜帶 lastIndex 在他們之間,這使得 test() 交替 true 和 false - 重新建立模式或重置 lastIndex.
正規表示式中的前瞻是什麼?
前瞻斷言某物確實存在或不存在't跟隨,而不消耗它。 foo(?=bar) 比賽 foo 只有當 bar 接下來是; foo(?!bar) 僅當它不匹配時才匹配't。向後看(((?<=...), (?<!...)) 向後做同樣的事情,並且已經登陸現代 JavaScript、Python 和 PCRE - 但沒有登陸 Go' RE2,它完全拒絕兩者。密碼規則是經典用途: ^(?=.*\d)(?=.*[a-z]).{8,}$ 堆疊斷言,以便在同一位置獨立檢查每個要求。
如何將電話號碼與正規表示式相符?
對於特定的格式,要明確而不是聰明: ^\(\d{3}\) \d{3}-\d{4}$ 比賽 (555) 123-4567。 若要容忍不同的分隔符,請允許選擇性的分隔符,例如 ^\+?1?[-.\s]?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$. 不同國家的電話號碼很混亂,因此僅在儲存之前驗證您實際接受的格式並標準化為數字 - 在信任模式之前建立並測試即時模式。
包裹起來
當我開始在即時測試儀中建立模式而不是在編輯器中猜測時,Regex 從我最可怕的技能變成了我最常用的技能之一。開始簡單,測試真實和對抗性的輸入,尊重災難性的回溯,並保留您信任的個人模式庫。
的 正規表示式建構器 在 toolz。dev 上,透過即時匹配、群組突出顯示和標記切換,使循環快速進行 - 所有這些都在瀏覽器中運行,因此您的測試資料保持私有。當您的模式提取 JSON 時,請將其交給 json 格式化程式;當它捕獲 Base64 blob 時,用 解碼它 Base64 轉換器。 或瀏覽所有 600 多個免費工具 工具。dev.



