正則表達式小記

来源:https://www.cnblogs.com/jiasm/archive/2018/03/26/8653587.html
-Advertisement-
Play Games

什麼是正則表達式 正則表達式是用於匹配字元串中字元組合的模式。在 JavaScript中,正則表達式也是對象。這些模式被用於 RegExp 的 exec 和 test 方法, 以及 String 的 match、replace、search 和 split 方法。 正則表達式存在於大部分的編程語言, ...


什麼是正則表達式

正則表達式是用於匹配字元串中字元組合的模式。在 JavaScript中,正則表達式也是對象。
這些模式被用於 RegExp 的 exec 和 test 方法, 以及 String 的 matchreplacesearch 和 split 方法。

正則表達式存在於大部分的編程語言,就算是在寫shell時也會不經意的用到正則。
比如大家最喜歡的rm -rf ./*,這裡邊的*就是正則的通配符,匹配任意字元。

JavaScript也有正則表達式的實現,差不多就長這個樣子:/\d/(匹配一個數字)。
個人認為正則所用到的地方還是很多的,比如模版字元的替換、解析URL,表單驗證 等等一系列。
如果在Node.js中用處就更為多,比如請求頭的解析、文件內容的批量替換以及寫爬蟲時候一定會遇到的解析HTML標簽。

正則表達式在JavaScript中的實現

JavaScript中的語法

贅述那些特殊字元的作用並沒有什麼意義,浪費時間。
推薦MDN的文檔:基礎的正則表達式特殊字元

關於正則表達式,個人認為以下幾個比較重要:

貪婪模式與非貪婪模式

P.S. 關於貪婪模式非貪婪模式,發現有些地方會拿這樣的例子:

1 /.+/ // 貪婪模式
2 /.+?/ // 非貪婪模式

 

僅僅拿這樣簡單的例子來說的話,有點兒扯淡

 1 // 假設有這樣的一個字元串
 2 let html = '<p><span>text1</span><span>text2</span></p>'
 3 
 4 // 現在我們要取出第一個`span`中的文本,於是我們寫了這樣的正則
 5 html.match(/<span>(.+)<\/span>/)
 6 // 卻發現匹配到的竟然是 text1</span><span>text2
 7 // 這是因為 我們括弧中寫的是 `(.+)` .為匹配任意字元, +則表示匹配一次以上。
 8 // 當規則匹配到了`text1`的時候,還會繼續查找下一個,發現`<`也命中了`.`這個規則
 9 // 於是就持續的往後找,知道找到最後一個span,結束本次匹配。
10 
11 // 但是當我們把正則修改成這樣以後:
12 html.match(/<span>(.+?)<\/span>/)
13 // 這次就能匹配到我們想要的結果了
14 // `?`的作為是,匹配`0~1`次規則
15 // 但是如果跟在`*`、`+`之類的表示數量的特殊字元後,含義就會變為匹配儘量少的字元。
16 // 當正則匹配到了text1後,判斷後邊的</span>命中了規則,就直接返回結果,不會往後繼續匹配。

 

簡單來說就是:

  1. 貪婪模式,能拿多少拿多少
  2. 非貪婪模式,能拿多拿多少

捕獲組

/123(\d+)0/ 括弧中的被稱之為捕獲組。

捕獲組有很多的作用,比如處理一些日期格式的轉換。

1 let date = '2017-11-21'
2 
3 date.replace(/^(\d{4})-(\d{2})-(\d{2})$/, '$2/$3/$1')

 

又或者可以直接寫在正則表達式中作為前邊重覆項的匹配。

 1 let template = 'hello helloworl'
 2 template.match(/(\w+) \1/) // => hello hello
 3 
 4 // 我們可以用它來匹配出month和day數字相同的數據
 5 let dateList = `
 6 2017-10-10
 7 2017-11-12
 8 2017-12-12
 9 `
10 
11 dateList.match(/^\d{4}-(\d{2})-(\1)/gm) // => ["2017-10-10", "2017-12-12"]

 

非捕獲組

我們讀取了一個文本文件,裡邊是一個名單列表
我們想要取出所有Stark的名字(但是並不想要姓氏,因為都叫Stark),我們就可以寫這樣的正則:

1 let nameList = `
2 Brandon Stark
3 Sansa Stark
4 John Snow
5 `
6 
7 nameList.match(/^\w+(?=\s?Stark)/gm) // => ["Brandon", "Sansa"]

 

上邊的(?=)就是非捕獲組,意思就是規則會被命中,但是在結果中不會包含它。

比如我們想實現一個比較常用的功能,給數組添加千分位:

1 function numberWithCommas (x = 0) {
2   return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
3 }
4 
5 numberWithCommas(123) // => 123
6 numberWithCommas(1234) // => 1,234

 

\B代表匹配一個非單詞邊界,也就是說,實際他並不會替換掉任何的元素。
其次,後邊的非捕獲組這麼定義:存在三的倍數個數字(3、6、9),並且這些數字後邊沒有再跟著其他的數字。
因為在非捕獲組中使用的是(\d{3})+,貪婪模式,所以就會儘可能多的去匹配。
如果傳入字元串1234567,則第一次匹配的位置在12之間,第二次匹配的位置在45之間。
獲得的最終字元串就是1,234,567

如何使用正則表達式

RegExp對象

創建RegExp對象有兩種方式:

  1. 直接字面量的聲明:/\d/g
  2. 通過構造函數進行創建:new RegExp('\d', 'g')

RegExp對象提供了兩個方法:

exec

方法執行傳入一個字元串,然後對該字元串進行匹配,如果匹配失敗則直接返回null
如果匹配成功則會返回一個數組:

1 let reg = /([a-z])\d+/
2 let str = 'a233'
3 let result = reg.exec(str) // => ['a233', 'a', ...]

 

P.S. 如果正則表達式有g標識,在每次執行完exec後,該正則對象的lastIndex值就會被改變,該值表示下次匹配的開始下標

1 let reg = /([a-z])\d+/g
2 let str = 'a233'
3 reg.exec(str) // => ['a233', 'a', ...]
4 // reg.lastIndex = 4
5 reg.exec(str) // => null

 

test

方法用來檢查正則是否能成功匹配該字元串

1 let reg = /^Hello/
2 
3 reg.test('Hello World') // => true
4 reg.test('Say Hello') // => false

 

test方法一般來說多用在檢索或者過濾的地方。
比如我們做一些篩選filter的操作,用test就是一個很好的選擇。

1 // 篩選出所有名字為 Niko的數據
2 let data = [{ name: 'Niko Bellic' }, { name: 'Roman Bellic'}]
3 
4 data.filter(({name}) => /^Niko/.test(name)) // => [{ name: 'Niko Bellic' }]

 

String對象

除了RegExp對象實現的一些方法外,String同樣提供了一套方法供大家來使用。

傳入一個正則表達式,並使用該表達式進行匹配;
如果匹配失敗,則會返回-1
如果匹配成功,則會返回匹配開始的下標。
可以理解為是一個正則版的indexOf

1 'Hi Niko'.search(/Niko/) // => 3
2 'Hi Niko'.search(/Roman/) // => -1
3 
4 // 如果傳入的參數為一個字元串,則會將其轉換為`RegExp`對象
5 'Hello'.search('llo') // => 2

 

split

split方法應該是比較常用的,用得最多的估計就是[].split(',')了。。

然而這個參數也是可以塞進去一個正則表達式的。

 1 '1,2|3'.split(/,|\|/) // => [1, 2, 3]
 2 
 3 // 比如我們要將一個日期時間字元串進行分割
 4 let date = '2017-11-21 23:40:56'
 5 
 6 date.split(/-|\s|:/)
 7 
 8 // 又或者我們有這麼一個字元串,要將它正確的分割
 9 let arr = '1,2,3,4,[5,6,7]'
10 
11 arr.split(',') // => ["1", "2", "3", "4", "[5", "6", "7]"] 這個結果肯定是不對的。
12 
13 // 所以我們可以這麼寫
14 arr.split(/,(?![,\d]+])/) // => ["1", "2", "3", "4", "[5,6,7]"]

 

該條規則會匹配,,但是,後邊還有一個限定條件,那就是絕對不能出現數字+,的組合併且以一個]結尾。
這樣就會使[4,5,6]裡邊的,不被匹配到。

match

match方法用來檢索字元串,並返回匹配的結果。

如果正則沒有添加g標識的話,返回值與exec類似。
但是如果添加了g標識,則會返回一個數組,數組的item為滿足匹配條件的子串。
這將會無視掉所有的捕獲組。
拿上邊的那個解析HTML來說

1 let html = '<p><span>text1</span><span>text2</span></p>'
2 
3 html.match(/<span>(.+?)<\/span>/g) // => ["<span>text1</span>", "<span>text2</span>"]

 

replace

replace應該是與正則有關的應用最多的一個函數。
最簡單的模版引擎可以基於replace來做。
日期格式轉換也可以通過replace來做。
甚至match的功能也可以通過replace來實現(雖說代碼會看起來很醜)

replace接收兩個參數
replace(str|regexp, newStr|callback)

第一個參數可以是一個字元串 也可以是一個正則表達式,轉換規則同上幾個方法。
第二個參數卻是可以傳入一個字元串,也可以傳入一個回調函數。

當傳入字元串時,會將正則所匹配到的字串替換為該字元串。
當傳入回調函數時,則會在匹配到子串時調用該回調,回調函數的返回值會替換被匹配到的子串。

1 'Hi: Jhon'.replace(/Hi:\s(\w+)/g, 'Hi: $1 Snow') // => Hi: Jhon Snow
2 
3 'price: 1'.replace(/price:\s(\d)/g, (/* 匹配的完整串 */str, /* 捕獲組 */ $1) => `price: ${$1 *= 10}`) // => price: 10

 

一些全新的特性

前段時間看了下ECMAScript 2018的一些草案,發現有些Stage 3的草案,其中有提到RegExp相關的,併在chrome上試驗了一下,發現已經可以使用了。

Lookbehind assertions(應該可以叫做回溯引用吧)

同樣也是一個非捕獲組的語法定義

語法定義:

1 let reg = /(?<=Pre)\w/
2 
3 reg.test('Prefixer') // => true
4 reg.test('Prfixer') // => false

 

設置匹配串前邊必須滿足的一些條件,與(?=)正好相反,一前一後。
這個結合著(?=)使用簡直是神器,還是說解析HTML的那個問題。
現在有了(?<=)以後,我們甚至可以直接通過一個match函數拿到HTML元素中的文本值了。

1 let html = '<p><span>text1</span><span>text2</span></p>'
2 
3 html.match(/(?<=<span>)(.+?)(?=<\/span>)/g) // => ["text1", "text2"]

 

Named capture groups(命名捕獲組)

我們知道,()標識這一個捕獲組,然後用的時候就是通過\1或者$1來使用。
這次草案中提到的命名捕獲組,就是可以讓你對()進行命名,在使用時候可以用接近變數的用法來調用。

語法定義:

1 let reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
2 
3 '2017-11-21'.match(reg)

 

match的返回值中,我們會找到一個groupskey
裡邊存儲著所有的命名捕獲組。
Image
Image

在replace中的用法
1 let reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
2 '2017-11-21'.replace(reg, '$<month>/$<day>/$<year>') // => 21/11/2017

 

表達式中的反向引用
1 let reg = /\d{4}-(?<month>\d{2})-\k<month>/
2 reg.test('2017-11-11') // => true
3 reg.test('2017-11-21') // => false

 

參考資料


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 動畫 1.常規動畫屬性設置(可以同時選擇多個進行設置) UIViewAnimationOptionLayoutSubviews:動畫過程中保證子視圖跟隨運動。**提交動畫的時候佈局子控制項,表示子控制項將和父控制項一同動畫。** UIViewAnimationOptionAllowUserInteract ...
  • 先看看效果圖 一個消息列表,然後點擊item後會刷新時間,點擊置頂後也會刷新時間,置頂規則就是根據兩個欄位來排序 如果是置頂狀態,top為1,然後每次操作都會刷新 time的時間,time是存的時間戳,先看看實體類 package com.fragmentapp.home.bean; import ...
  • 最近在項目中經常用到UITableView中的cell中帶有UITextField或UITextView的情況,然後在這種場景下,當我們點擊屏幕較下方的cell進行編輯時,這時候鍵盤彈出來會出現遮擋待輸入的cell,導致我們無法很方便地查看到我們輸入的內容,這樣的體驗是非常不好的。這個問題在之前我們 ...
  • HTML5 是下一代的 HTML。 什麼是 HTML5? HTML5 將成為 HTML、XHTML 以及 HTML DOM 的新標準。 HTML 的上一個版本誕生於 1999 年。自從那以後,Web 世界已經經歷了巨變。 HTML5 仍處於完善之中。然而,大部分現代瀏覽器已經具備了某些 HTML5 ...
  • 剛纔被博客園官方移出首頁,不服,再發一遍,絕對原創,手打,思路清晰。 首先說一下,我不是阿裡的人,也沒去阿裡面試過,這是某微信群里的一個小伙伴給的,我現在的能力達不到阿裡的要求。不過人沒夢想還不如鹹魚,有能力的話還是想去嘗試一下。本文如有不足,請勿嘲諷,指出不足即可,謝謝。碼字不易,且看且珍惜,轉載 ...
  • 一、jQuery的封裝擴展 1、jQuery中extend方法使用 (掛在到jQuery和jQuery.fn兩對象身上的使用) 1.1、官方文檔定義: jQuery.extend Merge the contents of two or more objects together into the ...
  • 一、常見的web安全及防護原理 1.sql註入原理 就是通過把sql命令插入到web表單遞交或輸入功能變數名稱或頁面請求的查詢字元串,最終達到欺騙伺服器執行惡意的SQL命令。 防護,總的來說有以下幾點: 1、永遠不要信任用戶的輸入,要對用戶的輸入進行校驗,可以通過正則表達式,或限制長度,對單引號雙“--”進 ...
  • 在使用 Angular 進行開發中,我們常用到 Angular 中的綁定——模型到視圖的輸入綁定、視圖到模型的輸出綁定以及視圖與模型的雙向綁定。而這些綁定的值之所以能在視圖與模型之間保持同步,正是得益於Angular中的變化檢測。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...