<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                >[info] 部分內容摘自老姚的《JavaScript 正則表達式迷你書》,[鏈接](https://github.com/qdlaoyao/js-regex-mini-book)。 [TOC] # 貪婪匹配與惰性匹配 什么是正則表達式的貪婪與惰性匹配?來看下面這段代碼: ```js let str = "abcaxc" p1 = /ab.*c/ p2 = /ab.*?c/ console.log(p1.exec(str)) // [ 'abcaxc', index: 0, input: 'abcaxc', groups: undefined ] console.log(p2.exec(str)) // [ 'abc', index: 0, input: 'abcaxc', groups: undefined ] ``` 貪婪匹配:正則表達式一般趨向于最大長度匹配,也就是所謂的貪婪匹配。如上面使用模式 p1 匹配字符串 str,結果就是匹配到:`abcaxc` 惰性匹配:就是匹配到結果就好,盡可能少地匹配。如上面使用模式 p2 (p1 的惰性模式)匹配字符串 str,結果就是匹配到:`abc` 通過在量詞后面加個問號就能實現惰性匹配,比如下面這樣: | 貪婪量詞 | 惰性量詞 | | --- | --- | | {m, n} | {m, n}? | | {m, } | {m, }? | | ? | ?? | | + | +? | ```js var regex = /\d{2,5}/g var string = "123 1234 12345 123456" console.log( string.match(regex) ) // => ["123", "1234", "12345", "12345"] ``` ``` js var regex = /\d{2,5}?/g var string = "123 1234 12345 123456" console.log( string.match(regex) ) // => ["12", "12", "34", "12", "34", "12", "34", "56"] ``` # 位置匹配 位置(錨)是相鄰字符之間的位置。比如,下圖中箭頭所指的地方 ![](https://box.kancloud.cn/feca1993f09361ede170e2019aaeb6b2_701x159.png =400x) 如何匹配位置?在 ES5 中,共有 6 個錨: `^、$、\b、\B、(?=p)、(?!p)` 相應的可視化形式是: ![](https://box.kancloud.cn/54318cbe637d2a72630d094f9562d3c4_937x139.png ) ## ^ 和 $ ^(脫字符)匹配開頭,在多行匹配中匹配行開頭。 $(美元符號)匹配結尾,在多行匹配中匹配行結尾。 比如我們把字符串的開頭和結尾用 "#" 替換: ```js var result = "hello".replace(/^|$/g, '#'); console.log(result); // => "#hello#" ``` 多行匹配模式(即有修飾符 m)時,二者是行的概念,這一點需要我們注意 ```js var result = "I\nlove\njavascript".replace(/^|$/gm, '#'); console.log(result); /* #I# #love# #javascript# */ ``` ## \\b 和 \\B `\b`是單詞邊界,具體就是`\w`與`\W`之間的位置,也包括`\w`與`^`之間的位置,和`\w`與`$`之間的位置。 比如考察文件名`"[JS] Lesson\01.mp4"`中的`\b`,如下: ```js var result = "[JS] Lesson_01.mp4".replace(/\b/g, '#'); console.log(result); // => "[#JS#] #Lesson_01#.#mp4#" ``` `\B`就是`\b`的反面的意思,非單詞邊界。例如在字符串中所有位置中,扣掉`\b`,剩下的都是`\B`的 ```js var result = "[JS] Lesson_01.mp4".replace(/\B/g, '#'); console.log(result); // => "#[J#S]# L#e#s#s#o#n#_#0#1.m#p#4" ``` ## (?=p) 和 (?!p) `(?=p)`,其中 p 是一個子模式,即 p 前面的位置,或者說,該位置后面的字符要匹配 p。 比如`(?=l)`,表示 "l" 字符前面的位置,例如: ```js var result = "hello".replace(/(?=l)/g, '#'); console.log(result); // => "he#l#lo" ``` 而`(?!p)`就是`(?=p)`的反面意思,即該位置的后面不匹配 p: ```js var result = "hello".replace(/(?!l)/g, '#'); console.log(result); // => "#h#ell#o#" ``` ## 例題 千分符表示法一個常見的應用就是貨幣格式化。 比如把下面的字符串: `1888`格式化為`$ 1,888.00` ```js function format (num) { return num.toFixed(2).replace(/\B(?=(\d{3})+\b)/g, ",").replace(/^/, "$$ "); // replace 函數里兩個 $$ 才能表示美元符號,因為第二個參數 $ 有特殊含義 }; console.log(format(1888)); // => "$ 1,888.00" ``` # 正則表達式括號的作用 ## 分組 我們知道 `/a+/` 匹配連續出現的 `"a"`,而要匹配連續出現的 `"ab"` 時,需要使用 `/(ab)+/`。 其中括號是提供分組功能,使量詞 `+` 作用于 `"ab"` 這個整體,測試如下: ```js var regex = /(ab)+/g; var string = "ababa abbb ababab"; console.log( string.match(regex) ); // => ["abab", "ab", "ababab"] ``` ## 分支結構 在多選分支結構`(p1|p2)`中,此處括號的作用也是不言而喻的,提供了分支表達式的所有可能。 比如,要匹配如下的字符串: ```js I love JavaScript I love Regular Expression ``` 可以使用正則: ```js var regex = /^I love (JavaScript|Regular Expression)$/; console.log( regex.test("I love JavaScript") ); console.log( regex.test("I love Regular Expression") ); // => true // => true ``` 如果去掉正則中的括號,即`/^I love JavaScript|Regular Expression$/` 匹配字符串是 "I love JavaScript" 和 "Regular Expression",當然這不是我們想要的。 ## 替換 比如,想把 yyyy-mm-dd 格式,替換成 mm/dd/yyyy 怎么做? ```js var regex = /(\d{4})-(\d{2})-(\d{2})/; var string = "2017-06-12"; var result = string.replace(regex, "$2/$3/$1"); console.log(result); // => "06/12/2017" ``` 其中 replace 中的,第二個參數里用 $1、$2、$3 指代相應的分組 ## 反向引用 在正則本身里引用之前的分組,即反向引用,如 \\1 表示第一個分組 比如要寫一個正則支持匹配如下三種格式 ```js 2016-06-12 2016/06/12 2016.06.12 ``` ```js var regex = /\d{4}(-|\/|\.)\d{2}\1\d{2}/; var string1 = "2017-06-12"; var string2 = "2017/06/12"; var string3 = "2017.06.12"; var string4 = "2016-06/12"; console.log( regex.test(string1) ); // true console.log( regex.test(string2) ); // true console.log( regex.test(string3) ); // true console.log( regex.test(string4) ); // false ``` # JavaScript 中使用正則 ## RegExp 創建正則表達式,兩種寫法,一種是直接`/正則表達式/`,另一種是使用 RegExp 的構造方法 `new RegExp(pattern, attributes)`傳入的參數都為字符串/字符,第二個參數是修飾符 'i'、'g'、'm' >[danger]應該優先使用字面量形式,因為用構造函數會寫很多 \ ```js var re1 = /ABC\-001/ var re2 = new RegExp('ABC\\-001') re1 // /ABC\-001/ re2 // /ABC\-001/ ``` 一個 RegExp 對象有 exec 和 test 方法,比如上面的 re1 和 re2 可以這么使用`re1.test(str)` - test 方法檢索字符串是否滿足正則匹配。返回 true 或 false。 - exec 方法執行對字符串的正則匹配。返回一個數組包含相關信息(如果不滿足則返回 null)。 ```js let string = "2017.06.27" let reg = /\b(\d+)\b/g // \b 匹配單詞邊界 let result while (result = reg.exec(string)) { console.log(result, reg.lastIndex) } // => ["2017", "2017", index: 0, input: "2017.06.27"] 4 // => ["06", "06", index: 5, input: "2017.06.27"] 7 // => ["27", "27", index: 8, input: "2017.06.27"] 10 ``` exec 方法返回的數組的第 0 個元素是與正則表達式相匹配的文本,第 1 個元素是與 RegExpObject 的第 1 個分組相匹配的文本(如果有的話),第 2 個元素是與 RegExpObject 的第 2 個分組相匹配的文本(如果有的話),依次類推。 <br/> 除了數組元素和 length 屬性之外,exec() 方法還返回兩個屬性(可以通過res.input 和 res.index 來訪問)。index 屬性聲明的是匹配文本的第一個字符的位置。input 屬性則存放的是被檢索的字符串 string。我們可以看得出,在調用非全局的 RegExp 對象的 exec() 方法時,返回的數組與調用方法 String.match() 返回的數組是相同的。 <br/> 但是,當 RegExpObject 是一個**全局正則表達式**時,exec() 的行為就稍微復雜一些。它會在 RegExpObject 的 lastIndex 屬性指定的字符處開始檢索字符串 string。當 exec() 找到了與表達式相匹配的文本時,在匹配后,它將把 RegExpObject 的 lastIndex 屬性設置為匹配文本的**最后一個字符**的下一個位置。這就是說,您可以通過反復調用 exec() 方法來遍歷字符串中的所有匹配文本。當 exec() 再也找不到匹配的文本時,它將返回 null,并把 lastIndex 屬性重置為 0。 # 字符串中可以使用正則表達式的方法 ## match match() 方法只接受一個參數,要么是一個正則表達式,要么是一個 RegExp 對象 match() 方法將檢索字符串 stringObject,以找到一個或多個與 regexp 匹配的文本。這個方法的行為在很大程度上有賴于 regexp 是否具有標志 g。 <br/> 如果 regexp 沒有標志 g,那么 match() 方法就只能在 stringObject 中執行一次匹配。如果沒有找到任何匹配的文本, match() 將返回 null。否則,它將返回一個數組,其中存放了與它找到的匹配文本有關的信息。該數組的第 0 個元素存放的是匹配文本,而其余的元素存放的是與正則表達式的子表達式匹配的文本。除了這些常規的數組元素之外,返回的數組還含有兩個對象屬性。index 屬性聲明的是匹配文本的起始字符在 stringObject 中的位置,input 屬性聲明的是對 stringObject 的引用。 <br/> 如果 regexp 具有標志 g,則 match() 方法將執行全局檢索,找到 stringObject 中的所有匹配子字符串。若沒有找到任何匹配的子串,則返回 null。如果找到了一個或多個匹配子串,則返回一個數組。不過全局匹配返回的數組的內容與前者大不相同,它的數組元素中存放的是 stringObject 中所有的匹配子串,而且也沒有 index 屬性或 input 屬性。 可以看到,在全局檢索模式下,match() 既不提供與子表達式匹配的文本的信息,也不聲明每個匹配子串的位置。如果需要這些全局檢索的信息,可以使用 RegExp.exec()。 ```js var text = "cat, bat, sat, fat" var pattern = /.at/ // 與 pattern.exec(text) 相同 var matches = text.match(pattern) console.log(matches.index) // 0 console.log(matches[0]) // "cat" console.log(pattern.lastIndex) // 0 console.log(matches) // ['cat', index:0, input:'cat,bat,sat,fat' ] ``` ```js var text = "cat, bat, sat, fat" var pattern = /.at/g var matches = text.match(pattern) console.log(matches.index) // undefined console.log(matches[0]) // "cat" console.log(pattern.lastIndex) // 0 console.log(matches) // ['cat','bat','sat','fat'] ``` ## search 這個方法的唯一參數與 match() 方法的參數相同:由字符串或 RegExp 對象指定的一個正則表達式。search() 方法返回字符串中第一個匹配項的索引;如果沒有找到匹配項,則返回 -1。而且,search() 方法始終是從字符串開頭向后查找模式。 >[warning]似乎 RegExp 對象的 exec 和 test 方法可以完美地取代這兩個字符串方法? ## replace 這個方法接受兩個參數:第一個參數可以是一個 RegExp 對象或者一個字符串(這個字符串不會被轉換成正則表達式),第二個參數可以是一個字符串或者一個函數。如果第一個參數是字符串,那么只會替換第一個子字符串。**要想替換所有子字符串,唯一的辦法就是提供一個正則表達式,而且要指定全局(g)標志**,如下所示 ```js var text = "cat, bat, sat, fat" var result = text.replace("at", "ond") console.log(result) // "cond, bat, sat, fat" result = text.replace(/at/g, "ond") console.log(result) // "cond, bond, sond, fond" ``` 第二個參數,可以是字符串,也可以是函數。 當第二個參數是字符串時,如下的字符有特殊的含義: | 屬性 |描述| | --- | --- | |$1,$2,…,$99 |匹配第 1-99 個分組里捕獲的文本| |$&| 匹配到的子串文本| |$`| 匹配到的子串的左邊文本| |$' |匹配到的子串的右邊文本| |$$| 美元符號| 例如,把 "2,3,5",變成 "5=2+3": ```js var result = "2,3,5".replace(/(\d+),(\d+),(\d+)/, "$3=$1+$2") console.log(result) // => "5=2+3" ``` 當第二個參數是函數時,我們需要注意該回調函數的參數具體是什么: ```js "1234 2345 3456".replace(/(\d)\d{2}(\d)/g, function (match, $1, $2, index, input) { console.log([match, $1, $2, index, input]) }) // => ["1234", "1", "4", 0, "1234 2345 3456"] // => ["2345", "2", "5", 5, "1234 2345 3456"] // => ["3456", "3", "6", 10, "1234 2345 3456"] ``` 在正則表達式中定義了多個捕獲組的情況下,傳遞給函數的參數依次是模式的匹配項、第一個捕獲組的匹配項、第二個捕獲組的匹配項……,最后兩個參數分別是模式的匹配項在字符串中的位置(這個匹配項的第一個字符在字符串中的位置)和原始字符串。**這個函數應該返回一個字符串,表示應該被替換的匹配項。** ```js function htmlEscape (text) { return text.replace(/[<>"&]/g, function (match, pos, originalText) { switch (match) { case '<': return '&lt;' case '>': return '&gt;' case '&': return '&amp;' case '\"': return '&quot;' } }) } console.log(htmlEscape(`<p class="greeting">Hello world!</p>`)) // &lt;p class=&quot;greeting&quot;&gt;Hello world!&lt;/p&gt; ``` ## split split 也可以使用正則 ```js var regex = /\D/; console.log( "2017/06/26".split(regex) ); console.log( "2017.06.26".split(regex) ); console.log( "2017-06-26".split(regex) ); // => ["2017", "06", "26"] // => ["2017", "06", "26"] // => ["2017", "06", "26"] ``` # 例題 ## 1.使用正則表達式去除字符串中重復的字符 ``` js var str = "aaabbb___cccddd" str = str.replace(/(.)\1*/g, '$1') console.log(str) // ab_cd ``` `\1`用于正則表達式內取值,取的是第一個分組匹配到的值。 `$1`用于正則表達式外取值,?取的是第一個分組匹配到的值。 ## 2.驗證手機號 ``` js var reg = /^1[3578]\d{9}/ var str = '15616460659' console.log(reg.test(str)) // true ``` ## 3.寫函數實現任意標簽轉換成 json 形式 ```javaScript /* <div> <span> <a></a> </span> <span> <a></a> <a></a> </span> </div> */ function DOM2JSON(str) { let reg = /<(.+)>(.*?)<\/\1>/g // 注意 .\*? 是惰性匹配,如果使用 .\* 這樣的情況會出問題: <span><a></a></span><span></span> 不會最短地閉合 let result = null let nodes = [] while((result = reg.exec(str)) !== null) { // 當 exec() 再也找不到匹配項后它將返回 null,并把 lastIndex 屬性重置為 0 nodes.push({ tag: result[1], children: DOM2JSON(result[2])}) // exec 返回的數組,[0]匹配的字符串 然后依次是捕獲的分組 然后有 index 和 input 屬性 } return nodes.length > 1 ? nodes : nodes[0] } console.log(JSON.stringify(DOM2JSON('<div><span><a></a></span><span><a></a><a></a></span></div>'))) // {"tag":"div","children":[{"tag":"span","children":{"tag":"a"}},{"tag":"span","children":[{"tag":"a"},{"tag":"a"}]}]} ``` 這里主要利用了 exec 函數會在上一次匹配的結果之后繼續匹配,且如果未匹配成功會返回 null,然后注意下 exec 和正則表達式分組的使用即可。 ## 4.匹配 16 進制顏色 要求匹配: ```css #ffbbad #Fc01DF #FFF #ffE ``` 分析: 表示一個 16 進制字符,可以用字符組 [0-9a-fA-F]。 其中字符可以出現 3 或 6 次,需要是用量詞和分支結構。 使用分支結構時,需要注意順序。 ```js var regex = /#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})/g; var string = "#ffbbad #Fc01DF #FFF #ffE"; console.log( string.match(regex) ); // => ["#ffbbad", "#Fc01DF", "#FFF", "#ffE"] ``` ## 5.windows 操作系統文件路徑 要求匹配: ```shell F:\study\javascript\regex\regular expression.pdf F:\study\javascript\regex\ F:\study\javascript F:\ ``` 分析: 整體模式是: ```shell 盤符:\文件夾\文件夾\文件夾\ ``` 其中匹配 `"F:\"`,需要使用 `[a-zA-Z]:\\`,其中盤符不區分大小寫,注意 \ 字符需要轉義。 文件名或者文件夾名,不能包含一些特殊字符,此時我們需要排除字符組 `[^\\:*<>|"?\r\n/]`來表示合法字符。 另外它們的名字不能為空名,至少有一個字符,也就是要使用量詞 +。因此匹配 `文件夾\`,可用 `[^\\:*<>|"?\r\n/]+\\` 另外 `文件夾\`,可以出現任意次。也就是 `([^\\:*<>|"?\r\n/]+\\)*`。其中括號表示其內部正則是一個整體。 路徑的最后一部分可以是 文件夾,沒有 \,因此需要添加 `([^\\:*<>|"?\r\n/]+)?`。 ```js var regex = /^[a-zA-Z]:\\([^\\:*<>|"?\r\n/]+\\)*([^\\:*<>|"?\r\n/]+)?$/; console.log( regex.test("F:\\study\\javascript\\regex\\regular expression.pdf") ); // 在JavaScript 中字符串要表示字符 \\ 時,也需要轉義 console.log( regex.test("F:\\study\\javascript\\regex\\") ); console.log( regex.test("F:\\study\\javascript") ); console.log( regex.test("F:\\") ); // => true // => true // => true // => true ``` # 速查表 ## 字符組 | 模式 | 說明 | | --- | --- | | [abc] | 匹配 "a"、"b"、"c" 其中任意一個字符 | | [a-d1-4] | 匹配 "a"、 "b"、 "c"、 "d"、 "1"、 "2"、 "3"、 "4" 其中任意一個字符 | | [^abc] | 匹配除了 "a"、"b"、"c" 之外的任意一個字符 | | [^a-d1-4]] | 匹配除了 "a"、 "b"、 "c"、 "d"、"1"、 "2"、 "3"、"4" 之外的任意一個字符 | | . | 通配符,匹配除了少數字符 (\\n) 之外的任意字符 | | \d | 匹配數字,等價于 [0-9] | | \D | 匹配非數字,等價于 [^0-9] | | \w | 匹配單詞字符,等價于 [a-zA-Z0-9_] | | \W | 匹配非單詞字符,等價于 [^a-zA-Z0-9_] | | \s | 匹配空白符,等價于 [\\t \\v \\n \\r \\f] | | \S | 匹配非空白符,等價于 [^\\t \\v \\n \\r \\f] | ## 量詞 | 模式 | 說明 | | --- | --- | | {n, m} | 連續出現 n 到 m 次 | | {n, } | 至少連續出現 n 次 | | {n} | 連續出現 n 次 | | ? | 等價于 {0,1},0 次或 1 次 | | + | 等價于 {1, } 1 次及以上 | | * | 等價于 {0, } 0 次及以上 | ## 修飾符 | 符號 | 說明 | | --- | --- | | g | 全局匹配,找到所有滿足匹配的子串 | | i | 匹配過程中,忽略英文字母大小寫 | | m | 多行匹配,把 ^ 和 $ 變成行開頭和結尾 | ## 元字符轉義 所謂元字符,就是正則中有特殊含義的字符。 所有結構里,用到的元字符總結如下: `^`、`$`、`.`、`*`、`+`、`?`、`|`、`\`、`/`、`(`、`)`、`[`、`]`、`{`、`}`、`=`、`!`、`:`、`-` 當匹配上面的字符本身時,可以一律轉義: ```js var string = "^$.*+?|\\/[]{}=!:-,"; var regex = /\^\$\.\*\+\?\|\\\/\[\]\{\}\=\!\:\-\,/; console.log( regex.test(string) ); // => true ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看