日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

玩转JavaScript正则表达式

發布時間:2023/12/20 javascript 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 玩转JavaScript正则表达式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Why Regular Expression

我們先來看看,我們干哈要學正則表達式這玩意兒:

  • 復雜的字符串搜尋、替換工作,無法用簡單的方式(類似借助標準庫函數)達成。
  • 能夠幫助你進行各種字符串驗證。
  • 不止應用于編程語言中:JavaScript、JAVA、Perl、PHP、C#...
  • 也應用于許多操作系統的主流指令中:Linux/Unix、Mac、Windows PowerScript

在我們常用的開發工具中,如Fiddler Willow、WebStorm、Vim,正則表達式也能幫助我們方便的進行Find&Replace的工作。由于正則表達式的流派很多,這篇文章主要是描述JavaScript中的正則表達式。

介紹點語法

定義

所謂正則表達式,就是一種描述字符串結構模式的形式化表達方法。

這是《精通正則表達式》對于它的定義,反正我看了這句話還是不知道正則表達式是干嘛用的,不過沒關系,下面我們先來看一下JavaScript的正則表達式中一些常用的語法。

創建方式

在JavaScript中,我們可以通過RegExp()構造函數或者RegExp直接量兩種方式去創建正則表達式。

var pattern1 = /s$/; var pattern2 = new RegExp('s$');

上面代碼中的pattern1和pattern2是等價的,都是用來匹配所有以字母s結尾的字符串。

多說兩句:

在創建變量時,對于布爾、數值、字符串、null和undefined這個五個原始值類型來說,原始類型優于封裝對象,原因如下。

1、不同于字符串直接量,new出來的String是一個真正的對象,這意味著你不能使用內置操作符來比較兩個截然不同的String對象的內容。

var s = new String('hello'); typeof 'hello'; // string typeof s; // object var s1 = new String('hello'); var s2 = new String('hello'); s1 === s2; // false

這是因為每個String對象對是一個單獨的對象,其總是只等于其自身。使用不嚴格相等運算符也是一樣。

s1 == s2; // false

2、在ES5規范中,就像[],{}這樣的對象直接量一樣,程序運行時每次碰到RegExp直接量都會創建新對象。比如,如果在循環體中寫var pattern = /s$/,則每次遍歷都會創建一個新的正則表達式對象。然而在ES3規范中一個正則表達式直接量會在執行到它時轉換為一個RegExp對象,同一段代碼的正則表達式直接量的每次運算都返回同一個對象。而ES5做了相反的規定。用下面這段代碼做比較。

function getRE() {var re = /[a-z]/; re.foo = 'bar'; return re; } var reg = getRE(); re2 = getRE(); console.log(reg === re2); // 在ES3中返回true,在ES5中返回false reg.foo = 'baz'; console.log(re2.foo); // 在ES3中返回'baz',在ES5中返回'bar'

顯然ES5的規范更符合開發者的期望。

各種表格

直接量字符

字符匹配
字母和數字字符自身
\oNUL字符
\t制表符(\u0009)
\n換行符(\u000A)
\v垂直制表符(\u000B)
\f換頁符(\u000C)
\r回車符(\u000D)
\xnn由十六進制數nn指定的拉丁字符
\uxxx由十六進制數xxxx指定的Unicode字符
\cX控制字符^X

注:

由十六進制數nn指定的拉丁字符,例如:\x0A等價于\n
由十六進制數xxxx指定的Unicode字符:\u0009等價于\t
控制字符^X:\cJ等價于換行符\n
如果不記得哪些標點符號需要反斜桿轉義,可以在每個標點符號前都加上反斜桿。

字符類

字符匹配
[...]方括號內任意字符
[^...]不在方括號內的任意字符
.除換行符和Unicode行終止符外的任意字符
\w任何ASCⅡ字符組成的單詞,等價于[a-zA-Z0-9_]
\W任何不是ASCⅡ字符組成的單詞,等價于[^a-zA-Z0-9_]
\s任何Unicode空白符
\S任何非Unicode空白符,注意\w和\S的不同
\d任何ASCⅡ數字,等價于[0-9]
\D除了ASCⅡ數字之外的任何字符,等價于[^0-9]
[\b]退格直接量

注:

方括號又叫字符組,注意某些元字符在字符組外和字符組內的意義不同。例如:^在字符組外匹配行的開頭,在字符組內表示排除型字符;-在字符組外匹配普通連字符號,在字符組內(不在開頭)表示一個范圍;問號和點號在字符組外通常是元字符,但在字符組內只是匹配普通字符而已。

重復字符類

字符匹配
{n,m}匹配前一項至少n次,但不能超過m次
{n,}匹配前一項n次或多次
{n}匹配前一項n次
?匹配前一項0次或1次,也就是說前一項是可選的,等價于{0,1}
+匹配前一項1次或多次,等價于{1,}
*匹配前一項0次或多次,等價于{0,}

注:

javascript默認是貪婪匹配,也就是說匹配重復字符是盡可能多地匹配,而且允許后續的正則表達式繼續匹配。而進行非貪婪匹配,只需要在待匹配的字符后面跟隨一個問號即可:“??”、“+?”、“*?”、“{1,5}?”。比如:/a+/可以匹配一個或多個連續的字母a。當使用“aaa”作為匹配字符串時,/a+/會匹配它的三個字母。但是/a+?/會盡可能少的匹配,只能匹配第一個哦~

選擇、分組和引用字符

字符匹配
"豎線"選擇,匹配的是該符號左邊的子表達式或右邊的子表達式
(...)組合,將幾個項組合為一個單元,這個單元可通過“*”、“+”、“?”和"豎線"等符號修飾,而且可以記住和這個相匹配的字符串以供伺候的引用使用
(?:...)只組合,把項組合到一個單元,但不記憶與該組相匹配的字符
\n和第n個分組第一次匹配的字符相匹配,組是圓括號中的子表達式(也有可能是嵌套),組索引是從左到右的左括號數,“(?:”形式的分組不編碼

錨字符

字符匹配
^匹配字符串的開頭,在多行檢索中,匹配一行的開頭
$匹配字符串的結尾,在多行檢索中,匹配一行的結尾
\b匹配一個單詞的邊界,簡而言之,就是位于字符\w和字符\W之間的位置,或位于字符\w和字符串的開頭或結尾之間的位置(但需要注意的是在字符組內[\b]匹配的是退格符)
\B匹配非單詞邊界的位置
(?=p)零寬正向先行斷言,要求接下來的字符都與p匹配,但不能包括匹配p的那些字符
(?!p)零寬負向先行斷言,要求接下來的字符不與p匹配

修飾符

字符匹配
i執行不區分大小寫的匹配
g執行一個全局匹配,簡而言之,即找到所有的匹配,而不是在找到第一個之后就停止
m多行匹配模式,^匹配一行的開頭和字符串的開頭,$匹配行的結束和字符串的結束

用于模式匹配的String方法

方法意義
String.search()參數:一個正則表達式。返回:第一個與參數匹配的子串的起始位置,如果找不到,返回-1。不支持全局搜索,如果參數是字符串,會先通過RegExp構造函數轉換成正則表達式。
String.replace()檢索和替換。第一個參數:正則表達式,第二個參數:要進行替換的字符串,也可以是函數。設置了g修飾符,則替換所有匹配的子串,否則只替換第一個子串。通過在替換字符串中使用“$n”,可以使用子表達式相匹配的文本來替換字符。
String.match()參數:一個正則表達式。返回:一個由匹配結果組成的數組。設置g則返回所有匹配結果,否則數組的第一個元素是匹配的字符串,剩下的是圓括號中的子表達式,即a[n]中存放的是$n的內容。
String.split()參數:正則表達式或字符串。返回:子串組成的數組。

RegExp對象

RegExp構造函數

var pattern = new RegExp(arg1, arg2);

arg1: 正則表達式中兩條斜桿之間的文本

arg2: 可選,指定修飾符:g,m,i

作用:動態創建正則表達式,例如待檢索的字符串是由用戶輸入的。

RegExp的屬性

屬性意義
source只讀字符串,包含正則表達式的文本。
global只讀布爾值,是否帶修飾符g
ignoreCase只讀布爾值,是否帶修飾符i
multiline只讀布爾值,是否帶修飾符m
lastIndex可讀寫整數,如果帶g修飾符,這個屬性儲存在整個字符串中下一次檢索開始的位置,這個屬性會被exec()和test()方法用到。

RegExp的方法

方法意義
exec()參數:字符串。在一個字符串中執行匹配檢索,與String.macth()非全局檢索類似,返回一個數組或null。
test()參數:字符串。返回true or false
toString()轉換成字符串形式

關于RegExp對象的屬性和方法多說兩句:

RegExp對象的屬性index包含了發生匹配的字符位置,屬性input引用的是正在檢索的字符串。
當調用exec()或test()的正則表達式具有修飾符g時,它將把當前正則表達式對象的lastIndex屬性設置為緊挨著匹配子串的字符位置。如果沒發現任何匹配結果,lastIndex將重置為0。可以通過此特性反復調用exec()或test()來遍歷字符串。

ES5中,正則表達式直接量的每次計算都會創建一個新的RegExp對象,每個新的RegExp對象具有各自的lastIndex屬性,這勢必會大大減少“殘留”lastIndex屬性對程序造成的意外影響。

一些栗子

?

?

匹配URL

常見的URL:http://hostname/path.html當然,.htm或.shtml的結尾也很常見,或者干脆沒有path部分,還包括http或https的協議頭。

  • 其實hostname的規則比較復雜,但是跟在http(s)://之后的就有可能是主機名,所以這個部分先簡單的用[-a-z0-9_.]來匹配,再加上可能存在的端口號,所以再加上:, 就成了[-a-z0-9_.:]。

  • path部分變化更多,所以需要使用[-a-z0-9_:@&?=+,.!/~*%$]來匹配。注意,連字符必須放在字符組的開頭,保證它是一個普通字符,而不是用來表示范圍。

  • 綜合起來,我們得到的正則表達式就是:var patternURL = /https?:\/\/[a-z0-9_.:]+\/[-a-z0-9_:@&?=+,.!/~*%$]*(\.(html|htm|shtml))?/

  • 因為我們降低了對匹配的要求,所以'http://.../foo.html' 這種顯然不是合法URL的字符串也能匹配,不過我覺得還好,畢竟我們需要在正則匹配的復雜性和完整性之間取得平衡。

  • 接下來,我們一步步地對URL進行分析。

    我們可以將URL分為三個部分:

  • 協議頭:^http://或^https://

  • 主機名:主機名是位于^http://之后和第一個反斜桿(如果有的話)之前的內容。

  • 路徑:除了上面兩者之外的內容。

  • 得到正則表達式:var patternURL = /^https?:\/\/([^/]+)(/.*)?$/

  • 由于URL可能包含端口號,它位于主機名和路徑之間,以冒號開頭:?(:(\d)+)?

  • 得到正則表達式:var patternURL = /^https?:\/\/([^/:]+)(:(\d)+)?(/.*)?$/

  • 匹配合法的主機名:由點號分隔部分組成,每個部分可以包括ASCⅡ字符、數字和連字符,但不能以連字符開頭和結尾。則可以得到:var patternHostname = /[a-z0-9]|[a-z0-9][-a-z0-9]*[a-z0-9]/i

  • 結尾的后綴部分只有有限個可能:(com|edu|gov|int|mil|net|org|biz|info|name|museum|coop|aero|[a-z][a-z])

  • 完善后得到:var patternHostname =/^([a-z0-9]\.|[a-z0-9][-a-z0-9]{0,61}[a-z0-9]\.)(com|edu|gov|int|mil|net|org|biz|info|name|museum|coop|aero|[a-z][a-z])$/i

  • 匹配HTML Tag

    匹配HTML標簽嘛,感覺很簡單的樣子,我們的第一反應可能是:var pattern = /<[^>]+>/
    不過這樣匹配可能存在的問題是:如果tag中含有>,上面的正則就不能正常匹配了。如:

    <input name=123 value=">" >

    雖然上面這種HTML的寫法很少(sha)見(bi),但確實合法的。因此,簡單的<[^>]+>就不能用了,需要想個聰明點的辦法。

    我們先來看一下HTML Tag中有什么規則:<...>中能夠出現

  • 引用文本(被單引號或雙引號包裹的)
  • 非引用形式的“其他文本”(包括除了>和引號之外的任何字符)
  • 引用文本:HTML中的引文可以用雙引號,也可以用單引號,但不允許嵌套轉義的引號。

    因此我們可以使用/("[^"]*"|'[^']*')/來匹配。

    其他文本:除了>和引號之外的任意字符

    可以使用/[^'">]/來匹配
    現在可以得出匹配HTML Tag的正則表達式最終版!

    var pattern = /<("[^"]*"|'[^']*'|[^'">])*>/

    給這個正則表達式來點注釋:

    < # 開始的尖括號"<"( # 任意數量的..."[^"]*" # 雙引號字符串| # 或者是...'[^']*' # 單引號字符串 | # 或者是... [^'">] # "其他文本" )* # > # 結束的尖括號">"

    需要注意的是,我們不用"+"來修飾[^'">]的原因是([^'">]+)*可能會帶來災難性的后果。匹配次數呈指數級增長。比如:對于簡單的目標字符串helloworld,是星號會迭代10次,每一次迭代中[^'">]+匹配一個字符?還是星號迭代3次,內部的[^'">]+分別匹配5、2、3個字符?或者2、3、1、4個字符?還是其他情況?這樣會把正則引擎搞瘋掉的啦!

    匹配String

    其實匹配引號內字符串的最簡單辦法是用這個表達式:/"[^"]*"/。

    不過我們要容許其中包含轉義的引號,例如:"we have a \"awesome\" world!"。

    下面進行任務分解:

  • 匹配起始引號
  • 匹配正文
  • 匹配結束引號
  • 不過由于轉義之后的引號也能夠出現的正文中,所以處理起來比較棘手哈。

    我們還是以"we have a \"awesome\" world!"為例子。如果JavaScript中有逆序環視(lookaround)可用,我們可以這樣寫:var pattern = /"([^"]|(?<=\\)")*"/。

    但是這個正則表達式無法匹配下面這兩個無聊的例子:"/-|-\\" or "[^-^]"
    我本來想匹配"/-|-\\",結果匹配的確是"/-|-\\" or "。

    注:

    這里的結束分隔符是一個引號,但正文也可能包含轉義之后的引號。匹配開始和結束分隔符很容易,訣竅就在于,匹配正文的時候不要超越結束分隔符。

    匹配正文的思路:1、不是引號:由[^"]匹配。2、是一個引號,而它左邊又有一個反斜桿,那么這個引號也屬于正文。使用逆序環視:/"([^"]|(?<=\\)")*"/

    鑒于上面的例子,我們需要對var pattern = /"([^"]|(?<=\\)")*"/進行修改!

    第一個表達式的問題在于,我們把反斜桿認為只是用來轉義引號的,其實反斜桿在字符串中可以用來轉義任何字符。因此,我們要匹配的文本其實是開始引號和結束引號之間,包括轉義字符和非引號的任何字符。得到:/"(\\.|[^"])*"/

    不過!

    上面的表達式還是會錯誤的匹配:"You need a new\"world\" haha.?中的"You need a new\"world\"?即使這并不是一個字符串。

    因為,這個表達式一開始匹配到了引號之后的文本,如果找不到結束的引號,它就會回溯。而[^"]匹配到了world\里的反斜桿后,之后的那個引號會被表達式認為是一個結束的引號。。。

    繼續改改改!

    所以我們需要保證,字符串里的反斜桿不能以[^"]方式匹配。要將[^"]改為[^\\"]
    上面的正則表達式使用了JavaScript正則表達式并不茲瓷的逆序環視,這里給出JavaScript支持的版本。

    /(["'])(((\\.|[^\1\\])*)+)\1/?或者?/^(['"])(((\\['"])?([^\1])*)+)\1/

    好了,由于本人筆力有限,關于JavaScript的正則表達式只能介紹到這里,感興趣的同學可以去閱讀犀牛書的第十章以及《精通正則表達式》這本書

    原文鏈接:http://ivweb.io/topic/56e804ef1a5f05dc50643106

    本文編輯:宋秉金

    總結

    以上是生活随笔為你收集整理的玩转JavaScript正则表达式的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。