JS正則表達式

@(javascript)[js正則表達式]

[toc]

JS正則表達式

正則表達式一直是一個令人頭疼但卻又是十分重要的一個東西。熟練的使用正則表達式可以讓你的工作事半功倍。接下來,一起來看看正則表達式是什么吧!

正則表達式概念

正則表達式,又稱規則表達式。(英語:Regular Expression,在代碼中常簡寫為regex、regexp或RE),計算機科學的一個概念。正則表通常被用來檢索、替換那些符合某個模式(規則)的文本。

正則表達式的基本語法

var reg = / pattern / flags;

就像上面的,正則表達式是由兩個/符號包裹起來的,兩個/里面的(上面的pattern)就是需要的任何簡單或者是復雜的正則表達式。而在第二個/后面是一個或者是多個標志(flags),用來標明正則表達式的行為。
flags有以下五種行為:

  • g:表示全局(global)模式,即在匹配到第一個后繼續匹配
  • i:忽略(ignore)大小寫
  • m:便是多行(multiline)模式,即到達一行時繼續查找下一行
  • y:(ES6新增的粘連修飾符)
  • u:(ES6新增)

正則的規則分類

下面根據JavaScript正則表達式的速查表中的分類來對每一下進行一個說明。

正則表達式基礎

基礎里面呢主要有6需要記憶的東西,分別是:

  • .:匹配除了換行以外其他所有字符
  • a:匹配字符a,衍生為匹配單個字母
  • ab:匹配字符串ab,衍生為匹配字符串
  • a|b:匹配a或者b,就是或者的意思
  • a*:匹配一次或者是多次a
  • \:轉義符號,轉義一個特殊的字符
// `.`的使用
var reg = /./g;
var text = "abcdefg";
var res = text.match(reg);
console.log(res); // (7) ["a", "b", "c", "d", "e", "f", "g"]

// `a`的使用
var reg = /A/gi; // 全局匹配。忽略大小寫
var text = "abcdefg";
var res = text.match(reg);
console.log(res); // (7) ["a"]

// `ab`的使用
var reg = /AbCdef/gi; // 全局匹配。忽略大小寫
var text = "abcdefg";
var res = text.match(reg);
console.log(res); // (7) ["abcdef"]

// `a|b`的使用 一
var reg = /a|b|c|d/; // 非全局匹配。
var text = "abcdefg";
var res = text.match(reg);
console.log(res); // ["a", index: 0, input: "abcdefg"]

// `a|b`的使用 二
var reg = /a|b|c|d/g; // 全局匹配。
var text = "abcdefg";
var res = text.match(reg);
console.log(res); // (4) ["a", "b", "c", "d"]。使用全局匹配。會在匹配對后繼續匹配

// `a*`的使用
var reg = /a*/; 
var text = "abcdcba";
var res = text.match(reg);
console.log(res); // ["a", index: 0, input: "abcdcba"]

// `a*`的使用
var reg = /a*/g; // 全局匹配。
var text = "abcdcba";
var res = text.match(reg);
console.log(res); // (8) ["a", "", "", "", "", "", "a", ""]。使用全局匹配會把之后沒有匹配到的轉化為空字符串

// `\`的使用  回到第一個 . 的使用那里。如果我把 . 前面加一個 \ 符號,那么這個點就是一個普通的點了
var reg = /\./g; // 全局匹配。
var text = "abcdefg";
var res = text.match(reg);
console.log(res); // null

JavaScript中需要使用 \ 的特殊符號有:( ) [ ] { } . | + * ? \ ^ $ 以及 空白

正則表達式字符類

  • [ab-d]:a,b,c,d四個字符中的一個,衍生為使用[],那就是匹配其中的一個
  • [^ab-d]:除了a,b,c,d四個字符其他的任意字符,衍生為使用[^]可以排除[]里面的東西
  • [\b]:退格字符,了解
  • \d:一個0-9的數字
  • \D:一個非數字
  • \s:一個空白字符
  • \S:一個非空白字符
  • \w:匹配一個字母,數字或者是下劃線
  • \W:匹配一個除字母,數字,下劃線之外的任意字符
// `[a-z]`的使用
var reg = /[a-z]/g; // 全局匹配。匹配 a-z 的任意一個,因為是全局匹配。所以會一直找。但是不會有 1234
var text = "abcd1234";
var res = text.match(reg);
console.log(res); // (4) ["a", "b", "c", "d"]

// `[a-z]`的使用
var reg = /[^a-z]/g; // 全局匹配。匹配 除了 a-z 的任意一個。所以是 1 2 3 4。因為是全局匹配。所以會一直找
var text = "abcd1234";
var res = text.match(reg);
console.log(res); // (4) ["1", "2", "3", "4"]

// `[\b]`的使用
var reg = /[\b]/g; // 全局匹配。匹配 \b,當然也可以匹配其他的特殊轉義字符,見 正則表達式特殊字符
var text = "abcd\b1234";
var res = text.match(reg);
console.log(res); // (4) ["1", "2", "3", "4"]

// `\d`,`\D`,`\s`,`\S`,`\w`,`\W`的使用
var reg = /\D\d/g; // 全局匹配。匹配一個非數字與一個數字。兩者緊靠在一起  注意順序
var text = "abcd1234";
var res = text.match(reg);
console.log(res); // ["d1"]
// 如果是下面的一個,則匹配 null
var reg = /\D\d/g; // 全局匹配。匹配一個數字與一個非數字。兩者緊靠在一起  注意順序
var text = "abcd1234";
var res = text.match(reg);
console.log(res); // null
// 匹配一個
var reg = /\D\s\w\d/g; // 全局匹配。注意順序  注意大小寫
var text1 = "abcd1234";
var text2 = "abcd _1234";
var res1 = text1.match(reg);
var res2 = text2.match(reg);
console.log(res1); // null
console.log(res2); // ["d _1"]

正則表達式量詞

  • *:匹配0次或者多次。等價于{0,}
  • +:匹配一次或者多次。等價于{1,}
  • ?:匹配0次或者一次。等價于{0,1}
  • {2}:只匹配2
  • {2, 5}:匹配2-5
  • {2,}:匹配2次或者多次

這里涉及到一個貪婪匹配非貪婪匹配
貪婪匹配指的是使用以上量詞的時候會按照最大次數進行匹配。
非貪婪匹配則是按最小次數進行匹配。

使用非貪婪匹配只需在兩次后面加上一個?

// `*`的使用
// 非全局匹配。
var reg = /[a-z]*/; // 匹配 a-z 的0個或者多個
var text = "abcd1234";
var res = text.match(reg);
console.log(res); // ["abcd", index: 0, input: "abcd1234"]
// 全局匹配。
var reg = /[a-z]*/g; // 匹配 a-z 的0個或者多個
var text = "abcd1234";
var res = text.match(reg);
console.log(res); // (6) ["abcd", "", "", "", "", ""]。當匹配為 0 個的時候,會變成空字符串。對比 + 號

// `+`的使用
// 非全局匹配。
var reg = /[a-z]+/; // 匹配 a-z 的0個或者多個
var text = "abcd1234";
var res = text.match(reg);
console.log(res); // ["abcd", index: 0, input: "abcd1234"]
// 全局匹配。
var reg = /[a-z]+/g; // 匹配 a-z 的0個或者多
var text = "abcd1234";
var res = text.match(reg);
console.log(res); // ["abcd"]。因為至少匹配一個,所以不會有空字符串。對比 * 號

// `?`的使用
// 非全局匹配。
var reg = /[a-z]?/; // 匹配 a-z 的0個或者一個
var text = "abcd1234";
var res = text.match(reg);
console.log(res); // ["a", index: 0, input: "abcd1234"]。匹配到一個就停下來
// 全局匹配。
var reg = /[a-z]?/g; // 匹配 a-z 的0個或者一個
var text = "abcd1234";
var res = text.match(reg);
console.log(res); // ["a", "b", "c", "d", "", "", "", "", ""]。abcd匹配到了。1234則是空字符串。

以上說的都屬于貪婪匹配。都是按最多個匹配的。如果是非貪婪匹配。則是按照最少的次數匹配。

// `*`的使用
// 非全局匹配。貪婪匹配
var reg = /[a-z]*/; // 匹配 a-z 的0個或者多個
var text = "abcd1234";
var res = text.match(reg);
console.log(res); // ["abcd", index: 0, input: "abcd1234"]
// 全局匹配。貪婪匹配
var reg = /[a-z]*/g; // 匹配 a-z 的0個或者多個
var text = "abcd1234";
var res = text.match(reg);
console.log(res); // (6) ["abcd", "", "", "", "", ""]。當匹配為 0 個的時候,會變成空字符串。對比 + 號

// 非全局匹配。非貪婪匹配
var reg = /[a-z]*?/; // 匹配 a-z 的0個或者多個
var text = "abcd1234";
var res = text.match(reg);
console.log(res); // ["", index: 0, input: "abcd1234"]
// 全局匹配。非貪婪匹配
var reg = /[a-z]*?/g; // 匹配 a-z 的0個或者多個
var text = "abcd1234";
var res = text.match(reg);
console.log(res); // (9) ["", "", "", "", "", "", "", "", ""]

以上就是貪婪匹配非貪婪匹配的區別。不過不管是如何。在匹配是0次的時候。空字符串的個數總是匹配不成功部分的字符串的長度+1

正則表達式捕獲組與非捕獲組

  • (...):捕獲組
  • (?...):非捕獲組
  • \Y:匹配第Y個被捕獲的組(也稱反向引用)。其中Y是一個數字,這個數組取值范圍是*,即{0,}。但是建議反向引用不要索引大于9的捕獲性分組。
捕獲組
var reg = /ab(cd(1234))/;
var text = "abcd1234";
var res = text.match(reg);
console.log(res); // (3) ["abcd1234", "cd1234", "1234", index: 0, input: "abcd1234"]

分析:

  1. 捕獲組就是在匹配 ()外面的字符之后在匹配 () 里面的。結果中的 "abcd1234"
  2. 捕獲組里面還有捕獲組會先忽略里面的捕獲組匹配在一次匹配里面的捕獲組。結果中的"cd1234""1234"
非捕獲組
var reg = /ab(?:cd(1234))/;
var text = "abcd1234";
var res = text.match(reg);
console.log(res); // (3) ["abcd1234", "1234", index: 0, input: "abcd1234"]

分析:非捕獲組就是不捕獲,就行上面的結果中沒有了"cd1234"

那么捕獲與非捕獲有什么區別呢? 記得看寵物小精靈的時候小智看見新的小精靈扔球抓小精靈的時候就屬于一個捕獲,如果看見不扔球那就是不捕獲。那捕獲和不捕獲有什么區別呢?就行抓小精靈一樣,抓住了之后就可以用了嘛!所以被捕獲的東西之后是可以使用的。那么怎么使用呢? 問得好。這時候就需要使用到\Y 了。

var reg1 = /(a)/;
var reg2 = /(a)\1/; // 相當于是 /(a)a/
var text1 = "aabb1234";
var text2 = "aabb1234";
var res1 = text1.match(reg1);
var res2 = text2.match(reg2);
console.log(res1); // ["a", "a", index: 0, input: "aabb1234"]
console.log(res2); // ["aa", "a", index: 0, input: "aabb1234"]

上面的例子中,reg1reg2 僅僅有一點不同。但是匹配后的東西是不同的。簡單地說,就是,使用 \Y 后會賦值第Y個捕獲的組。以下代碼說明通過$Y來接收相應的捕獲組。不能從0開始

\Y
var reg = /ab(cd(1234))/;
var text = "abcd1234";
var res = text.match(reg);
console.log(res); // (3) ["abcd1234", "cd1234", "1234", index: 0, input: "abcd1234"]
console.log(RegExp.$0); // undefined
console.log(RegExp.$1); // cd1234
console.log(RegExp.$2); // 1234
var res1 = text.replace(reg,"$1$2"); // 使用 $1 $2 取出捕獲組的內容
console.log(res1); // cd12341234

正則表達式斷言

  • ^:字符串的開始必須是
  • $:字符串的結尾必須是
  • \b:匹配文字(單詞)邊界
  • \B:非文字(單詞)邊界
  • (?=...):積極的前瞻(也叫前瞻或者是順序肯定環視)
  • (?!...):消極的前瞻(也加后瞻或者是順序否定環視)
^$的使用
var reg = /^b.*\d$/; // 要求字符 b 開頭,中間 * 個任意字符(除換行符),必須以數字結束
var text1 = "abcd1234";
var text2 = "bcd";
var text3 = "bcd1234";
var res1 = text1.match(reg);
var res2 = text2.match(reg);
var res3 = text3.match(reg);
console.log(res1); // null
console.log(res2); // null
console.log(res3); // ["bcd1234", index: 0, input: "bcd1234"]
\b\B的使用
var reg = /\bhi\b/; // 
var text1 = "hi"; 
var text2 = "him"; 
var text3 = "history";
var res1 = text1.match(reg);
var res2 = text2.match(reg);
var res3 = text3.match(reg);
console.log(res1); // ["hi", index: 0, input: "hi"]
console.log(res2); // null
console.log(res3); // null
積極的前瞻 (?=...) 積極的前瞻 匹配后面是 ... 的位置,不捕獲匹配結果
var reg = /abcd(?=1234)/;
var text = "abcd1234";
var text1 = "abcdefg";
var res = text.match(reg);
var res1 = text1.match(reg);
console.log(res) // ["abcd", index: 0, input: "abcd1234"]
console.log(res1) // null

看上面的例子可以看出積極的前瞻匹配1234前面的abcd,不匹配def前面的abcd;而消極的前瞻恰恰相反,看下面的例子。

消極的前瞻 (?!...) 消極的前瞻 匹配后面不是 ... 的位置,不捕獲匹配結果
var reg = /abcd(?!=1234)/;
var text = "abcd1234";
var text1 = "abcdefg";
var res = text.match(reg);
var res1 = text1.match(reg);
console.log(res) // null
console.log(res1) // ["abcd", index: 0, input: "abcd1234"]

正則表達式特殊字符

  • \n:換行符
  • \r:回車符
  • \t:制表符
  • \0:空字符
  • \YYY:8進制字符
  • \xYY:十六進制字符
  • \uYYYY:十六進制字符
  • \cY:控制符
    正則的特殊字符在實際中運用的比較少,具體的用法與之前講到的[\b]類似。上面的兩個十六進制字符中,\xYY主要匹配數字字母等。而\uYYYY則是為了匹配漢字以及以下特殊的符號。

正則表達式替換

正則表達式替換主要是替換一些字符。主要以下幾個,可是在replace中使用。

  • $$:插入$
  • $&:插入整個匹配
  • $`:插入匹配項前面的字符串
  • $':插入匹配項后面的字符串
  • $Y:插入第Y個捕獲的組
var reg = /.{2}水(.)/;
var text = "君子之交淡如水,小人之交甘若醴";
var res = text.match(reg);
console.log(res); // (2) ["淡如水,", ",", index: 4, input: "君子之交淡如水,小人之交甘若醴"]
$$:插入$
var reg = /.{2}水(.)/;
var text = "君子之交淡如水,小人之交甘若醴";
var newStr = text.replace(reg,"$$");
console.log(newStr); // 君子之交$小人之交甘若醴
$&:插入整個匹配
var reg = /.{2}水(.)/;
var text = "君子之交淡如水,小人之交甘若醴";
var newStr = text.replace(reg,"$&");
console.log(newStr); // 君子之交淡如水,小人之交甘若醴
$`:插入匹配項前面的字符串
var reg = /.{2}水(.)/;
var text = "君子之交淡如水,小人之交甘若醴";
var newStr = text.replace(reg,"$`");
console.log(newStr); // 君子之交君子之交小人之交甘若醴
$':插入匹配項后面的字符串
var reg = /.{2}水(.)/;
var text = "君子之交淡如水,小人之交甘若醴";
var newStr = text.replace(reg,"$'");
console.log(newStr); // 君子之交小人之交甘若醴小人之交甘若醴
$Y:插入第Y個捕獲的組
var reg = /.{2}水(.)/;
var text = "君子之交淡如水,小人之交甘若醴";
var newStr = text.replace(reg,"$1");
console.log(newStr); // 君子之交,小人之交甘若醴

正則表達式實例的方法

exec() 最主要的方法

此方法專門為捕獲組設計的。此方法接收一個參數,及需要測試的字符串。返回數組或者是null。但返回的值包含兩個額外的屬性:
index:匹配性在字符串中的位置
input:應用正則的表達式

var reg = /你(我他(與她))/
var text = "你我他與她";
var res = reg.exec(text);
console.log(res); //(3) ["你我他與她", "我他與她", "與她", index: 0, input: "你我他與她"]

["你我他與她", "我他與她", "與她", index: 0, input: "你我他與她"]的結果。使用res[下標]可以查看具體的匹配下。從第二項開始才是捕獲項。使用res.indexres.input查看起始位置與匹配的字符串。

exec()方法始終返回一項,如果設置了全局匹配g,只會從上一次結束的敵法繼續查找,而不會返回多項。

var text = "bat, cat, fat";

var reg1 = /.at/;
var res = reg1.exec(text);
console.log(res.index); // 0
console.log(res[0]);    // bat

var res = reg1.exec(text);
console.log(res.index); // 0
console.log(res[0]);    // bat

var reg2 = /.at/g;

var res = reg2.exec(text);
console.log(res.index); // 0
console.log(res[0]);    // bat

var res = reg2.exec(text);
console.log(res.index); // 5
console.log(res[0]);    // cat

test()方法

接收一個字符串作為參數,返回:
true:匹配
false:不匹配

var text = "abcd1234";
var reg1 = /\D/g;
var reg2 = /\s/g;
var res1 = reg1.test(text);
console.log(res1);  // true
var res2 = reg2.test(text);
console.log(res2);  // false

關于使用RegExp構造函數

語法:var reg = new RegExp(參數1[,參數2]);

var reg = new RegExp("\D","gi");
var text = "ABd1234";
var res = reg.exec(text);
console.log(res); // ["d", index: 2, input: "ABd1234"]

看上面的例子。兩個參數需要使用字符串
但是,上面的例子有一個問題。沒有按照我們所想的出現一個A,而是一個d。同時,我們忽略大小寫在看一下:

var reg = new RegExp("\D","g");
var text = "ABd1234";
var res = reg.exec(text);
console.log(res); // null

所以,使用構造函數還有一個需要注意的就是所有的元字符都需要雙重轉義。將上面的代碼換為下面的看看

var reg = new RegExp("\\D","g");
var text = "ABd1234";
var res = reg.exec(text);
console.log(res); // ["A", index: 0, input: "ABd1234"]

注意上面的\\D。這個才表示一個元字符。剛剛的就是一個\一個D。所以。在正則的構造函數中使用元字符需要雙重轉義

附上幾個常用的正則匹配

電話號碼匹配:/^1[3-8]\d{9}$/
電子郵件:/[a-zA-z0-9_-]{6,12}@[a-zA-z0-9_-]+\.[a-zA-z0-9]+/
匹配特定了的郵件:/[a-zA-z0-9_-]{6,12}@(163|qq|gmail)\.com/

更多的匹配可查閱:最全的常用正則表達式大全

以上就是關于正則的一些使用概念以及使用方法。如果想要熟練的使用正則去匹配或者是修改字符串。還是需要不斷的練習才是。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,983評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,772評論 3 422
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,947評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,201評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,960評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,350評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,406評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,549評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,104評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,914評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,089評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,647評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,340評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,753評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,007評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,834評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,106評論 2 375

推薦閱讀更多精彩內容